nexpose 0.2.8 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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