nexpose 0.2.8 → 0.5.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.
data/lib/nexpose/group.rb CHANGED
@@ -8,35 +8,33 @@ module Nexpose
8
8
  #
9
9
  # @return [Boolean] Whether group deletion succeeded.
10
10
  #
11
- def asset_group_delete(id)
11
+ def delete_asset_group(id)
12
12
  r = execute(make_xml('AssetGroupDeleteRequest', {'group-id' => id}))
13
13
  r.success
14
14
  end
15
15
 
16
- alias_method :delete_asset_group, :asset_group_delete
17
-
18
- # Retrieve a list of all asset groups the user is authorized to view or
16
+ # Retrieve an array of all asset groups the user is authorized to view or
19
17
  # manage.
20
18
  #
21
19
  # @return [Array[AssetGroupSummary]] Array of AssetGroupSummary objects.
22
20
  #
23
- def asset_groups
21
+ def list_asset_groups
24
22
  r = execute(make_xml('AssetGroupListingRequest'))
25
23
 
26
- res = []
24
+ groups = []
27
25
  if r.success
28
26
  r.res.elements.each('AssetGroupListingResponse/AssetGroupSummary') do |group|
29
- res << AssetGroupSummary.new(group.attributes['id'].to_i,
30
- group.attributes['name'].to_s,
31
- group.attributes['description'].to_s,
27
+ groups << AssetGroupSummary.new(group.attributes['id'].to_i,
28
+ group.attributes['name'],
29
+ group.attributes['description'],
32
30
  group.attributes['riskscore'].to_f)
33
31
  end
34
32
  end
35
- res
33
+ groups
36
34
  end
37
35
 
38
- alias_method :asset_groups_listing, :asset_groups
39
- alias_method :groups, :asset_groups
36
+ alias_method :groups, :list_asset_groups
37
+ alias_method :asset_groups, :list_asset_groups
40
38
  end
41
39
 
42
40
  # Summary value object for asset group information.
@@ -53,7 +51,7 @@ module Nexpose
53
51
  # @param [Connection] connection Connection to security console.
54
52
  #
55
53
  def delete(connection)
56
- connection.asset_group_delete(@id)
54
+ connection.delete_asset_group(@id)
57
55
  end
58
56
  end
59
57
 
@@ -71,13 +69,11 @@ module Nexpose
71
69
  end
72
70
 
73
71
  def save(connection)
74
- xml = %Q(<AssetGroupSaveRequest session-id='#{connection.session_id}'>)
72
+ xml = "<AssetGroupSaveRequest session-id='#{connection.session_id}'>"
75
73
  xml << to_xml
76
74
  xml << '</AssetGroupSaveRequest>'
77
- response = connection.execute(xml)
78
- if response.success
79
- @id = response.attributes['group-id'].to_i if @id < 0
80
- end
75
+ res = connection.execute(xml)
76
+ @id = res.attributes['group-id'].to_i if res.success and @id < 1
81
77
  end
82
78
 
83
79
  # Get an XML representation of the group that is valid for a save request.
@@ -87,12 +83,12 @@ module Nexpose
87
83
  # @return [String] XML representation of the asset group.
88
84
  #
89
85
  def to_xml
90
- xml = %Q(<AssetGroup id="#{@id}" name="#{@name}")
91
- xml << %Q( description="#{@description}") if @description
86
+ xml = %(<AssetGroup id="#{@id}" name="#{@name}")
87
+ xml << %( description="#{@description}") if @description
92
88
  xml << '>'
93
89
  xml << '<Devices>'
94
90
  @devices.each do |device|
95
- xml << %Q(<device id="#{device.id}"/>)
91
+ xml << %(<device id="#{device.id}"/>)
96
92
  end
97
93
  xml << '</Devices>'
98
94
  xml << '</AssetGroup>'
@@ -100,45 +96,45 @@ module Nexpose
100
96
 
101
97
  # Launch ad hoc scans against each group of assets per site.
102
98
  #
103
- # @param [Connection] connection Connection to console where asset group is configured.
104
- # @return [Array[Hash[Fixnum, Fixnum]]] Array of scan ID and engine ID
105
- # pairs for each scan launched.
99
+ # @param [Connection] connection Connection to console where asset group
100
+ # is configured.
101
+ # @return [Hash] Hash of site ID to Scan launch information for each scan.
106
102
  #
107
103
  def rescan_assets(connection)
108
- sites_ids = @devices.collect { |d| d.site_id }.uniq
109
- scans = []
104
+ sites_ids = @devices.map { |d| d.site_id }.uniq
105
+ scans = {}
110
106
  sites_ids.each do |id|
111
- dev_ids = @devices.select { |d| d.site_id == id }.map { |d| d.id }
112
- scans << connection.site_device_scan_start(id, dev_ids).merge(:site_id => id)
107
+ to_scan = @devices.select { |d| d.site_id == id }
108
+ scans[id] = connection.scan_devices(to_scan)
113
109
  end
114
110
  scans
115
111
  end
116
112
 
117
113
  # Load an existing configuration from a Nexpose instance.
118
114
  #
119
- # @param [Connection] connection Connection to console where asset group is configured.
115
+ # @param [Connection] connection Connection to console where asset group
116
+ # is configured.
120
117
  # @param [Fixnum] id Asset group ID of an existing group.
121
- # @return [AssetGroup] Asset group configuration loaded from a Nexpose console.
118
+ # @return [AssetGroup] Asset group configuration loaded from a Nexpose
119
+ # console.
122
120
  #
123
121
  def self.load(connection, id)
124
- r = APIRequest.execute(connection.url,
125
- %Q(<AssetGroupConfigRequest session-id="#{connection.session_id}" group-id="#{id}"/>))
122
+ xml = %(<AssetGroupConfigRequest session-id="#{connection.session_id}" group-id="#{id}"/>)
123
+ r = APIRequest.execute(connection.url, xml)
126
124
  parse(r.res)
127
125
  end
128
126
 
129
- alias_method :get, :load
130
-
131
127
  def self.parse(xml)
132
128
  return nil unless xml
133
129
 
134
130
  group = REXML::XPath.first(xml, 'AssetGroupConfigResponse/AssetGroup')
135
- asset_group = new(group.attributes['name'].to_s,
136
- group.attributes['description'].to_s,
131
+ asset_group = new(group.attributes['name'],
132
+ group.attributes['description'],
137
133
  group.attributes['id'].to_i,
138
134
  group.attributes['riskscore'].to_f)
139
135
  group.elements.each('Devices/device') do |dev|
140
136
  asset_group.devices << Device.new(dev.attributes['id'].to_i,
141
- dev.attributes['address'].to_s,
137
+ dev.attributes['address'],
142
138
  dev.attributes['site-id'].to_i,
143
139
  dev.attributes['riskfactor'].to_f,
144
140
  dev.attributes['riskscore'].to_f)
@@ -7,6 +7,7 @@ module Nexpose
7
7
  # supplied parameter. Console commands are documented in the
8
8
  # administrator's guide. If you use a command that is not listed in the
9
9
  # administrator's guide, the application will return the XMLResponse.
10
+ #
10
11
  def console_command(cmd_string)
11
12
  xml = make_xml('ConsoleCommandRequest', {})
12
13
  cmd = REXML::Element.new('Command')
@@ -26,6 +27,7 @@ module Nexpose
26
27
  # Obtain system data, such as total RAM, free RAM, total disk space,
27
28
  # free disk space, CPU speed, number of CPU cores, and other vital
28
29
  # information.
30
+ #
29
31
  def system_information
30
32
  r = execute(make_xml('SystemInformationRequest', {}))
31
33
 
@@ -42,6 +44,7 @@ module Nexpose
42
44
 
43
45
  # Induce the application to retrieve required updates and restart
44
46
  # if necessary.
47
+ #
45
48
  def start_update
46
49
  execute(make_xml('StartUpdateRequest', {})).success
47
50
  end
@@ -52,6 +55,7 @@ module Nexpose
52
55
  # shuts down as part of the restart process, it terminates any active
53
56
  # connections. Therefore, the application cannot issue a response when it
54
57
  # restarts.
58
+ #
55
59
  def restart
56
60
  execute(make_xml('RestartRequest', {})).success
57
61
  end
@@ -0,0 +1,142 @@
1
+ module Nexpose
2
+ module NexposeAPI
3
+ include XMLUtils
4
+
5
+ # Retrieve a list of all Scan Engine Pools managed by the Security Console.
6
+ #
7
+ # @return [Array[EnginePoolSummary]] Array of EnginePoolSummary objects
8
+ # associated with each engine associated with this security console.
9
+ #
10
+ def list_engine_pools
11
+ response = execute(make_xml('EnginePoolListingRequest'), '1.2')
12
+ arr = []
13
+ if response.success
14
+ response.res.elements.each('EnginePoolListingResponse/EnginePoolSummary') do |pool|
15
+ arr << EnginePoolSummary.new(pool.attributes['id'],
16
+ pool.attributes['name'],
17
+ pool.attributes['scope'])
18
+ end
19
+ end
20
+ arr
21
+ end
22
+
23
+ alias_method :engine_pools, :list_engine_pools
24
+ end
25
+
26
+ # A summary of an engine pool.
27
+ #
28
+ class EnginePoolSummary
29
+
30
+ # Unique identifier of the engine pool.
31
+ attr_reader :id
32
+ # Name of the engine pool.
33
+ attr_reader :name
34
+ # Whether the engine pool has global or silo scope.
35
+ attr_reader :scope
36
+
37
+ def initialize(id, name, scope = 'silo')
38
+ @id = id
39
+ @name = name
40
+ @scope = scope
41
+ end
42
+ end
43
+
44
+ # Engine pool configuration object.
45
+ #
46
+ class EnginePool
47
+
48
+ # Unique identifier of the engine pool.
49
+ attr_accessor :id
50
+ # Name of the engine pool.
51
+ attr_accessor :name
52
+ # Whether the engine pool has global or silo scope.
53
+ attr_accessor :scope
54
+ # Array containing (EngineSummary*) for each engine assigned to the pool.
55
+ attr_accessor :engines
56
+
57
+ def initialize(name, scope = 'silo', id = -1)
58
+ @name, @scope, @id = name, scope, id.to_i
59
+ @engines = []
60
+ end
61
+
62
+ # Add an engine to the pool by name (not ID).
63
+ #
64
+ # EngineSummary objects should just be appended to the pool directly,
65
+ # e.g., pool.engines << nsc.engines.find { |e| e.name == 'Cleveland' }
66
+ #
67
+ # @param [String] engine_name Name used to identify a paired scan engine.
68
+ #
69
+ def add(engine_name)
70
+ @engines << EngineSummary.new(-1, engine_name, nil, 40814, nil)
71
+ end
72
+
73
+ # Returns detailed information about a single engine pool.
74
+ #
75
+ # @param [Connection] connection Connection to console where site exists.
76
+ # @param [String] name The name of the engine pool.
77
+ # @param [String] silo The silo of the engine pool.
78
+ # @return [EnginePool] Engine pool configuration object.
79
+ #
80
+ def self.load(connection, name, scope = 'silo')
81
+ xml = %(<EnginePoolDetailsRequest session-id="#{connection.session_id}">)
82
+ xml << %(<EnginePool name="#{name}" scope="#{scope}"/>)
83
+ xml << '</EnginePoolDetailsRequest>'
84
+
85
+ r = connection.execute(xml, '1.2')
86
+ if r.success
87
+ r.res.elements.each('EnginePoolDetailsResponse/EnginePool') do |pool|
88
+ config = EnginePool.new(pool.attributes['name'],
89
+ pool.attributes['scope'],
90
+ pool.attributes['id'].to_i)
91
+ r.res.elements.each('EnginePoolDetailsResponse/EnginePool/EngineSummary') do |summary|
92
+ config.engines << EngineSummary.new(summary.attributes['id'].to_i,
93
+ summary.attributes['name'],
94
+ summary.attributes['address'],
95
+ summary.attributes['port'].to_i,
96
+ summary.attributes['status'],
97
+ summary.attributes['scope'])
98
+ end
99
+ return config
100
+ end
101
+ end
102
+ nil
103
+ end
104
+
105
+ # Save an engine pool to a security console.
106
+ #
107
+ # @param [Connection] connection Connection to console where site exists.
108
+ #
109
+ def save(connection)
110
+ request = @id > 0 ? 'EnginePoolUpdateRequest' : 'EnginePoolCreateRequest'
111
+ xml = %(<#{request} session-id="#{connection.session_id}">)
112
+ xml << '<EnginePool'
113
+ xml << %( id="#{@id}") if @id > 0
114
+ xml << %( name="#{@name}" scope="#{@scope}">)
115
+ @engines.each do |engine|
116
+ xml << %(<Engine name="#{engine.name}" />)
117
+ end
118
+ xml << '</EnginePool>'
119
+ xml << %(</#{request}>)
120
+
121
+ r = connection.execute(xml, '1.2')
122
+ if r.success
123
+ r.res.elements.each(request.gsub('Request', 'Response')) do |v|
124
+ return @id = v.attributes['id'].to_i
125
+ end
126
+ end
127
+ end
128
+
129
+ # Deletes an engine pool
130
+ #
131
+ # @param [Connection] connection Connection to console where site exists.
132
+ #
133
+ def delete(connection)
134
+ xml = %(<EnginePoolDeleteRequest session-id="#{connection.session_id}">)
135
+ xml << %(<EnginePool name="#{@name}" scope="#{@scope}" />)
136
+ xml << '</EnginePoolDeleteRequest>'
137
+
138
+ r = connection.execute(xml, '1.2')
139
+ r.success
140
+ end
141
+ end
142
+ end
@@ -6,6 +6,24 @@ module Nexpose
6
6
  module NexposeAPI
7
7
  include XMLUtils
8
8
 
9
+ # Provide a listing of all report definitions the user can access on the
10
+ # Security Console.
11
+ #
12
+ # @return [Array[ReportConfigSummary]] List of current report configuration.
13
+ #
14
+ def list_reports
15
+ r = execute(make_xml('ReportListingRequest'))
16
+ reports = []
17
+ if r.success
18
+ r.res.elements.each('//ReportConfigSummary') do |report|
19
+ reports << ReportConfigSummary.parse(report)
20
+ end
21
+ end
22
+ reports
23
+ end
24
+
25
+ alias_method :reports, :list_reports
26
+
9
27
  # Generate a new report using the specified report definition.
10
28
  def generate_report(report_id, wait = false)
11
29
  xml = make_xml('ReportGenerateRequest', { 'report-id' => report_id })
@@ -43,65 +61,31 @@ module Nexpose
43
61
  history.sort { |a, b| b.generated_on <=> a.generated_on }.first
44
62
  end
45
63
 
46
- # Delete a previously generated report definition.
47
- # Also deletes any reports generated from that configuration.
48
- def delete_report_config(report_config_id)
49
- xml = make_xml('ReportDeleteRequest', { 'reportcfg-id' => report_config_id })
50
- execute(xml).success
51
- end
52
-
53
64
  # Delete a previously generated report.
65
+ #
66
+ # @param [Fixnum] report_id ID of individual report to delete.
67
+ #
54
68
  def delete_report(report_id)
55
69
  xml = make_xml('ReportDeleteRequest', { 'report-id' => report_id })
56
70
  execute(xml).success
57
71
  end
58
72
 
59
- # Provide a list of all report templates the user can access on the
60
- # Security Console.
61
- def report_template_listing
62
- r = execute(make_xml('ReportTemplateListingRequest', {}))
63
- templates = []
64
- if r.success
65
- r.res.elements.each('//ReportTemplateSummary') do |template|
66
- templates << ReportTemplateSummary.parse(template)
67
- end
68
- end
69
- templates
70
- end
71
-
72
- alias_method :report_templates, :report_template_listing
73
-
74
- # Retrieve the configuration for a report template.
75
- def get_report_template(template_id)
76
- xml = make_xml('ReportTemplateConfigRequest', { 'template-id' => template_id })
77
- ReportTemplate.parse(execute(xml))
78
- end
79
-
80
- # Provide a listing of all report definitions the user can access on the
81
- # Security Console.
82
- def report_listing
83
- r = execute(make_xml('ReportListingRequest'))
84
- reports = []
85
- if r.success
86
- r.res.elements.each('//ReportConfigSummary') do |report|
87
- reports << ReportConfigSummary.parse(report)
88
- end
89
- end
90
- reports
91
- end
92
-
93
- alias_method :reports, :report_listing
94
-
95
- # Retrieve the configuration for a report definition.
96
- def get_report_config(report_config_id)
97
- xml = make_xml('ReportConfigRequest', { 'reportcfg-id' => report_config_id })
98
- ReportConfig.parse(execute(xml))
73
+ # Delete a previously generated report definition.
74
+ # Also deletes any reports generated from that configuration.
75
+ #
76
+ # @param [Fixnum] report_config_id ID of the report configuration to remove.
77
+ #
78
+ def delete_report_config(report_config_id)
79
+ xml = make_xml('ReportDeleteRequest', { 'reportcfg-id' => report_config_id })
80
+ execute(xml).success
99
81
  end
100
82
  end
101
83
 
102
84
  # Data object for report configuration information.
103
85
  # Not meant for use in creating new configurations.
86
+ #
104
87
  class ReportConfigSummary
88
+
105
89
  # The report definition (config) ID.
106
90
  attr_reader :config_id
107
91
  # The ID of the report template.
@@ -137,8 +121,10 @@ module Nexpose
137
121
  end
138
122
 
139
123
  # Summary of a single report.
124
+ #
140
125
  class ReportSummary
141
- # The id of the generated report.
126
+
127
+ # The ID of the generated report.
142
128
  attr_reader :id
143
129
  # The report definition (configuration) ID.
144
130
  attr_reader :config_id
@@ -193,6 +179,7 @@ module Nexpose
193
179
  attr_accessor :format
194
180
  attr_accessor :owner
195
181
  attr_accessor :time_zone
182
+ attr_accessor :language
196
183
 
197
184
  # Array of filters associated with this report.
198
185
  attr_accessor :filters
@@ -220,16 +207,17 @@ module Nexpose
220
207
  end
221
208
 
222
209
  def to_xml
223
- xml = %Q(<AdhocReportConfig format='#{@format}' template-id='#{@template_id}')
224
- xml << %Q( owner='#{@owner}') if @owner
225
- xml << %Q( timezone='#{@time_zone}') if @time_zone
210
+ xml = %(<AdhocReportConfig format='#{@format}' template-id='#{@template_id}')
211
+ xml << %( owner='#{@owner}') if @owner
212
+ xml << %( timezone='#{@time_zone}') if @time_zone
213
+ xml << %( language='#{@language}') if @language
226
214
  xml << '>'
227
215
 
228
216
  xml << '<Filters>'
229
217
  @filters.each { |filter| xml << filter.to_xml }
230
218
  xml << '</Filters>'
231
219
 
232
- xml << %Q(<Baseline compareTo='#{@baseline}' />) if @baseline
220
+ xml << %(<Baseline compareTo='#{@baseline}' />) if @baseline
233
221
 
234
222
  xml << '</AdhocReportConfig>'
235
223
  end
@@ -244,7 +232,7 @@ module Nexpose
244
232
  # @return Report in text format except for PDF, which returns binary data.
245
233
  #
246
234
  def generate(connection)
247
- xml = %Q{<ReportAdhocGenerateRequest session-id='#{connection.session_id}'>}
235
+ xml = %(<ReportAdhocGenerateRequest session-id='#{connection.session_id}'>)
248
236
  xml << to_xml
249
237
  xml << '</ReportAdhocGenerateRequest>'
250
238
  response = connection.execute(xml)
@@ -309,7 +297,8 @@ module Nexpose
309
297
 
310
298
  # Retrieve the configuration for an existing report definition.
311
299
  def self.load(connection, report_config_id)
312
- connection.get_report_config(report_config_id)
300
+ xml = %(<ReportConfigRequest session-id='#{connection.session_id}' reportcfg-id='#{report_config_id}'/>)
301
+ ReportConfig.parse(connection.execute(xml))
313
302
  end
314
303
 
315
304
  alias_method :get, :load
@@ -319,7 +308,7 @@ module Nexpose
319
308
  #
320
309
  # Returns the new configuration.
321
310
  def self.build(connection, site_id, site_name, type, format, generate_now = false)
322
- name = %Q{#{site_name} #{type} report in #{format}}
311
+ name = %(#{site_name} #{type} report in #{format})
323
312
  config = ReportConfig.new(name, type, format)
324
313
  config.frequency = Frequency.new(true, false)
325
314
  config.filters << Filter.new('site', site_id)
@@ -329,7 +318,7 @@ module Nexpose
329
318
 
330
319
  # Save the configuration of this report definition.
331
320
  def save(connection, generate_now = false)
332
- xml = %Q{<ReportSaveRequest session-id='#{connection.session_id}' generate-now='#{generate_now ? 1 : 0}'>}
321
+ xml = %(<ReportSaveRequest session-id='#{connection.session_id}' generate-now='#{generate_now ? 1 : 0}'>)
333
322
  xml << to_xml
334
323
  xml << '</ReportSaveRequest>'
335
324
  response = connection.execute(xml)
@@ -351,18 +340,22 @@ module Nexpose
351
340
  end
352
341
 
353
342
  def to_xml
354
- xml = %Q{<ReportConfig format='#{@format}' id='#{@id}' name='#{@name}' owner='#{@owner}' template-id='#{@template_id}' timezone='#{@time_zone}'>}
355
- xml << %Q{<description>#{@description}</description>} if @description
343
+ xml = %(<ReportConfig format='#{@format}' id='#{@id}' name='#{@name}' template-id='#{@template_id}')
344
+ xml << %( owner='#{@owner}') if @owner
345
+ xml << %( timezone='#{@time_zone}') if @time_zone
346
+ xml << %( language='#{@language}') if @language
347
+ xml << '>'
348
+ xml << %(<description>#{@description}</description>) if @description
356
349
 
357
350
  xml << '<Filters>'
358
351
  @filters.each { |filter| xml << filter.to_xml }
359
352
  xml << '</Filters>'
360
353
 
361
354
  xml << '<Users>'
362
- @users.each { |user| xml << %Q{<user id='#{user}' />} }
355
+ @users.each { |user| xml << %(<user id='#{user}' />) }
363
356
  xml << '</Users>'
364
357
 
365
- xml << %Q{<Baseline compareTo='#{@baseline}' />} if @baseline
358
+ xml << %(<Baseline compareTo='#{@baseline}' />) if @baseline
366
359
  xml << @frequency.to_xml if @frequency
367
360
  xml << @delivery.to_xml if @delivery
368
361
  xml << @db_export.to_xml if @db_export
@@ -412,7 +405,9 @@ module Nexpose
412
405
  # or raw_xml. If the vuln-status filter is not included in the configuration,
413
406
  # all the vulnerability test results (including invulnerable instances) are
414
407
  # exported by default in csv and raw_xml reports.
408
+ #
415
409
  class Filter
410
+
416
411
  # The ID of the specific site, group, device, or scan.
417
412
  # For scan, this can also be "last" for the most recently run scan.
418
413
  # For vuln-status, the ID can have one of the following values:
@@ -430,7 +425,7 @@ module Nexpose
430
425
  end
431
426
 
432
427
  def to_xml
433
- %Q{<filter id='#{@id}' type='#{@type}' />}
428
+ %(<filter id='#{@id}' type='#{@type}' />)
434
429
  end
435
430
 
436
431
  def self.parse(xml)
@@ -443,7 +438,9 @@ module Nexpose
443
438
  end
444
439
 
445
440
  # Data object associated with when a report is generated.
441
+ #
446
442
  class Frequency
443
+
447
444
  # Will the report be generated after a scan completes (true),
448
445
  # or is it ad hoc/scheduled (false).
449
446
  attr_accessor :after_scan
@@ -459,7 +456,7 @@ module Nexpose
459
456
  end
460
457
 
461
458
  def to_xml
462
- xml = %Q{<Generate after-scan='#{@after_scan ? 1 : 0}' schedule='#{@scheduled ? 1 : 0}'>}
459
+ xml = %(<Generate after-scan='#{@after_scan ? 1 : 0}' schedule='#{@scheduled ? 1 : 0}'>)
463
460
  xml << @schedule.to_xml if @schedule
464
461
  xml << '</Generate>'
465
462
  end
@@ -483,7 +480,9 @@ module Nexpose
483
480
  end
484
481
 
485
482
  # Data object for configuration of where a report is stored or delivered.
483
+ #
486
484
  class Delivery
485
+
487
486
  # Whether to store report on server.
488
487
  attr_accessor :store_on_server
489
488
  # Directory location to store report in (for non-default storage).
@@ -499,8 +498,8 @@ module Nexpose
499
498
 
500
499
  def to_xml
501
500
  xml = '<Delivery>'
502
- xml << %Q{<Storage storeOnServer='#{@store_on_server ? 1 : 0}'>}
503
- xml << %Q{<location>#{@location}</location>} if @location
501
+ xml << %(<Storage storeOnServer='#{@store_on_server ? 1 : 0}'>)
502
+ xml << %(<location>#{@location}</location>) if @location
504
503
  xml << '</Storage>'
505
504
  xml << @email.to_xml if @email
506
505
  xml << '</Delivery>'
@@ -526,7 +525,9 @@ module Nexpose
526
525
  end
527
526
 
528
527
  # Configuration structure for database exporting of reports.
528
+ #
529
529
  class DBExport
530
+
530
531
  # The DB type to export to.
531
532
  attr_accessor :type
532
533
  # Credentials needed to export to the specified database.
@@ -540,10 +541,10 @@ module Nexpose
540
541
  end
541
542
 
542
543
  def to_xml
543
- xml = %Q{<DBExport type='#{@type}'>}
544
+ xml = %(<DBExport type='#{@type}'>)
544
545
  xml << @credentials.to_xml if @credentials
545
546
  @parameters.each_pair do |name, value|
546
- xml << %Q{<param name='#{name}'>#{value}</param>}
547
+ xml << %(<param name='#{name}'>#{value}</param>)
547
548
  end
548
549
  xml << '</DBExport>'
549
550
  end
@@ -566,7 +567,9 @@ module Nexpose
566
567
  # The user_id, password and realm attributes should ONLY be used
567
568
  # if a security blob cannot be generated and the data is being
568
569
  # transmitted/stored using external encryption (e.g., HTTPS).
570
+ #
569
571
  class ExportCredential
572
+
570
573
  # Security blob for exporting to a database.
571
574
  attr_accessor :credential
572
575
  attr_accessor :user_id
@@ -580,9 +583,9 @@ module Nexpose
580
583
 
581
584
  def to_xml
582
585
  xml = '<credentials'
583
- xml << %Q{ userid='#{@user_id}'} if @user_id
584
- xml << %Q{ password='#{@password}'} if @password
585
- xml << %Q{ realm='#{@realm}'} if @realm
586
+ xml << %( userid='#{@user_id}') if @user_id
587
+ xml << %( password='#{@password}') if @password
588
+ xml << %( realm='#{@realm}') if @realm
586
589
  xml << '>'
587
590
  xml << @credential if @credential
588
591
  xml << '</credentials>'
@@ -600,213 +603,4 @@ module Nexpose
600
603
  nil
601
604
  end
602
605
  end
603
-
604
- # Data object for report template summary information.
605
- # Not meant for use in creating new templates.
606
- class ReportTemplateSummary
607
- # The ID of the report template.
608
- attr_reader :id
609
- # The name of the report template.
610
- attr_reader :name
611
- # One of: data|document. With a data template, you can export
612
- # comma-separated value (CSV) files with vulnerability-based data.
613
- # With a document template, you can create PDF, RTF, HTML, or XML reports
614
- # with asset-based information.
615
- attr_reader :type
616
- # The visibility (scope) of the report template. One of: global|silo
617
- attr_reader :scope
618
- # Whether the report template is built-in, and therefore cannot be modified.
619
- attr_reader :built_in
620
- # Description of the report template.
621
- attr_reader :description
622
-
623
- def initialize(id, name, type, scope, built_in, description)
624
- @id = id
625
- @name = name
626
- @type = type
627
- @scope = scope
628
- @built_in = built_in
629
- @description = description
630
- end
631
-
632
- def self.parse(xml)
633
- description = nil
634
- xml.elements.each('description') { |desc| description = desc.text }
635
- ReportTemplateSummary.new(xml.attributes['id'],
636
- xml.attributes['name'],
637
- xml.attributes['type'],
638
- xml.attributes['scope'],
639
- xml.attributes['builtin'] == '1',
640
- description)
641
- end
642
- end
643
-
644
- # Definition object for a report template.
645
- class ReportTemplate
646
- # The ID of the report template.
647
- attr_accessor :id
648
- # The name of the report template.
649
- attr_accessor :name
650
- # With a data template, you can export comma-separated value (CSV) files
651
- # with vulnerability-based data. With a document template, you can create
652
- # PDF, RTF, HTML, or XML reports with asset-based information. When you
653
- # retrieve a report template, the type will always be visible even though
654
- # type is implied. When ReportTemplate is sent as a request, and the type
655
- # attribute is not provided, the type attribute defaults to document,
656
- # allowing for backward compatibility with existing API clients.
657
- attr_accessor :type
658
- # The visibility (scope) of the report template.
659
- # One of: global|silo
660
- attr_accessor :scope
661
- # The report template is built-in, and cannot be modified.
662
- attr_accessor :built_in
663
- # Description of this report template.
664
- attr_accessor :description
665
-
666
- # Array of report sections.
667
- attr_accessor :sections
668
- # Map of report properties.
669
- attr_accessor :properties
670
- # Array of report attributes, in the order they will be present in a report.
671
- attr_accessor :attributes
672
- # Display asset names with IPs.
673
- attr_accessor :show_device_names
674
-
675
- def initialize(name, type = 'document', id = -1, scope = 'silo', built_in = false)
676
- @name = name
677
- @type = type
678
- @id = id
679
- @scope = scope
680
- @built_in = built_in
681
-
682
- @sections = []
683
- @properties = {}
684
- @attributes = []
685
- @show_device_names = false
686
- end
687
-
688
- # Save the configuration for a report template.
689
- def save(connection)
690
- xml = %Q{<ReportTemplateSaveRequest session-id='#{connection.session_id}' scope='#{@scope}'>}
691
- xml << to_xml
692
- xml << '</ReportTemplateSaveRequest>'
693
- response = connection.execute(xml)
694
- if response.success
695
- @id = response.attributes['template-id']
696
- end
697
- end
698
-
699
- def delete(connection)
700
- xml = %Q{<ReportTemplateDeleteRequest session-id='#{connection.session_id}' template-id='#{@id}'>}
701
- xml << '</ReportTemplateDeleteRequest>'
702
- response = connection.execute(xml)
703
- if response.success
704
- @id = response.attributes['template-id']
705
- end
706
- end
707
-
708
- # Retrieve the configuration for a report template.
709
- def self.load(connection, template_id)
710
- connection.get_report_template(template_id)
711
- end
712
-
713
- alias_method :get, :load
714
-
715
- include Sanitize
716
-
717
- def to_xml
718
- xml = %Q{<ReportTemplate id='#{@id}' name='#{@name}' type='#{@type}'}
719
- xml << %Q{ scope='#{@scope}'} if @scope
720
- xml << %Q{ builtin='#{@built_in}'} if @built_in
721
- xml << '>'
722
- xml << %Q{<description>#{@description}</description>} if @description
723
-
724
- unless @attributes.empty?
725
- xml << '<ReportAttributes>'
726
- @attributes.each do |attr|
727
- xml << %Q(<ReportAttribute name='#{attr}'/>)
728
- end
729
- xml << '</ReportAttributes>'
730
- end
731
-
732
- unless @sections.empty?
733
- xml << '<ReportSections>'
734
- properties.each_pair do |name, value|
735
- xml << %Q{<property name='#{name}'>#{replace_entities(value)}</property>}
736
- end
737
- @sections.each { |section| xml << section.to_xml }
738
- xml << '</ReportSections>'
739
- end
740
-
741
- xml << %Q{<Settings><showDeviceNames enabled='#{@show_device_names ? 1 : 0}' /></Settings>}
742
- xml << '</ReportTemplate>'
743
- end
744
-
745
- def self.parse(xml)
746
- xml.res.elements.each('//ReportTemplate') do |tmp|
747
- template = ReportTemplate.new(tmp.attributes['name'],
748
- tmp.attributes['type'],
749
- tmp.attributes['id'],
750
- tmp.attributes['scope'] || 'silo',
751
- tmp.attributes['builtin'])
752
- tmp.elements.each('//description') do |desc|
753
- template.description = desc.text
754
- end
755
-
756
- tmp.elements.each('//ReportAttributes/ReportAttribute') do |attr|
757
- template.attributes << attr.attributes['name']
758
- end
759
-
760
- tmp.elements.each('//ReportSections/property') do |property|
761
- template.properties[property.attributes['name']] = property.text
762
- end
763
-
764
- tmp.elements.each('//ReportSection') do |section|
765
- template.sections << Section.parse(section)
766
- end
767
-
768
- tmp.elements.each('//showDeviceNames') do |show|
769
- template.show_device_names = show.attributes['enabled'] == '1'
770
- end
771
-
772
- return template
773
- end
774
- nil
775
- end
776
- end
777
-
778
- # Section specific content to include in a report template.
779
- class Section
780
- # Name of the report section.
781
- attr_accessor :name
782
- # Map of properties specific to the report section.
783
- attr_accessor :properties
784
-
785
- def initialize(name)
786
- @name = name
787
- @properties = {}
788
- end
789
-
790
- include Sanitize
791
-
792
- def to_xml
793
- xml = %Q{<ReportSection name='#{@name}'>}
794
- properties.each_pair do |name, value|
795
- xml << %Q{<property name='#{name}'>#{replace_entities(value)}</property>}
796
- end
797
- xml << '</ReportSection>'
798
- end
799
-
800
- def self.parse(xml)
801
- name = xml.attributes['name']
802
- xml.elements.each("//ReportSection[@name='#{name}']") do |elem|
803
- section = Section.new(name)
804
- elem.elements.each("//ReportSection[@name='#{name}']/property") do |property|
805
- section.properties[property.attributes['name']] = property.text
806
- end
807
- return section
808
- end
809
- nil
810
- end
811
- end
812
606
  end