nexpose 7.0.0 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -3
- data/Gemfile.lock +1 -1
- data/lib/nexpose/ajax.rb +12 -16
- data/lib/nexpose/alert.rb +20 -21
- data/lib/nexpose/api.rb +3 -3
- data/lib/nexpose/asset.rb +23 -23
- data/lib/nexpose/blackout.rb +6 -14
- data/lib/nexpose/common.rb +87 -92
- data/lib/nexpose/connection.rb +8 -10
- data/lib/nexpose/console.rb +9 -9
- data/lib/nexpose/dag.rb +2 -2
- data/lib/nexpose/data_table.rb +8 -12
- data/lib/nexpose/device.rb +35 -34
- data/lib/nexpose/discovery.rb +69 -69
- data/lib/nexpose/discovery/filter.rb +7 -8
- data/lib/nexpose/engine.rb +22 -21
- data/lib/nexpose/error.rb +7 -5
- data/lib/nexpose/external.rb +21 -16
- data/lib/nexpose/filter.rb +51 -52
- data/lib/nexpose/global_blackout.rb +6 -7
- data/lib/nexpose/global_settings.rb +2 -3
- data/lib/nexpose/group.rb +25 -19
- data/lib/nexpose/json_serializer.rb +4 -14
- data/lib/nexpose/maint.rb +8 -9
- data/lib/nexpose/manage.rb +2 -2
- data/lib/nexpose/multi_tenant_user.rb +42 -42
- data/lib/nexpose/password_policy.rb +14 -14
- data/lib/nexpose/pool.rb +6 -5
- data/lib/nexpose/report.rb +30 -34
- data/lib/nexpose/report_template.rb +17 -18
- data/lib/nexpose/role.rb +64 -55
- data/lib/nexpose/scan.rb +77 -60
- data/lib/nexpose/scan_template.rb +17 -17
- data/lib/nexpose/scheduled_backup.rb +8 -8
- data/lib/nexpose/scheduled_maintenance.rb +9 -9
- data/lib/nexpose/shared_credential.rb +30 -33
- data/lib/nexpose/shared_secret.rb +5 -5
- data/lib/nexpose/silo.rb +68 -66
- data/lib/nexpose/silo_profile.rb +47 -50
- data/lib/nexpose/site.rb +101 -123
- data/lib/nexpose/site_credentials.rb +15 -17
- data/lib/nexpose/tag.rb +73 -80
- data/lib/nexpose/ticket.rb +45 -42
- data/lib/nexpose/user.rb +45 -45
- data/lib/nexpose/util.rb +1 -1
- data/lib/nexpose/version.rb +1 -1
- data/lib/nexpose/vuln.rb +45 -43
- data/lib/nexpose/vuln_def.rb +7 -7
- data/lib/nexpose/vuln_exception.rb +35 -36
- data/lib/nexpose/wait.rb +32 -28
- data/lib/nexpose/web_credentials.rb +34 -36
- metadata +2 -2
data/lib/nexpose/site.rb
CHANGED
@@ -22,7 +22,7 @@ module Nexpose
|
|
22
22
|
arr
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
alias sites list_sites
|
26
26
|
|
27
27
|
# Delete the specified site and all associated scan data.
|
28
28
|
#
|
@@ -69,7 +69,7 @@ module Nexpose
|
|
69
69
|
#
|
70
70
|
def completed_scans(site_id)
|
71
71
|
table = { 'table-id' => 'site-completed-scans' }
|
72
|
-
data
|
72
|
+
data = DataTable._get_json_table(self, "/data/scan/site/#{site_id}", table)
|
73
73
|
data.map(&CompletedScan.method(:parse_json))
|
74
74
|
end
|
75
75
|
end
|
@@ -158,21 +158,21 @@ module Nexpose
|
|
158
158
|
# @param [String] name Unique name of the site.
|
159
159
|
# @param [String] scan_template_id ID of the scan template to use.
|
160
160
|
def initialize(name = nil, scan_template_id = 'full-audit-without-web-spider')
|
161
|
-
@name
|
162
|
-
@scan_template_id
|
163
|
-
@id
|
164
|
-
@risk_factor
|
165
|
-
@config_version
|
166
|
-
@schedules
|
167
|
-
@blackouts
|
161
|
+
@name = name
|
162
|
+
@scan_template_id = scan_template_id
|
163
|
+
@id = -1
|
164
|
+
@risk_factor = 1.0
|
165
|
+
@config_version = 3
|
166
|
+
@schedules = []
|
167
|
+
@blackouts = []
|
168
168
|
@included_scan_targets = { addresses: [], asset_groups: [] }
|
169
169
|
@excluded_scan_targets = { addresses: [], asset_groups: [] }
|
170
|
-
@site_credentials
|
171
|
-
@shared_credentials
|
172
|
-
@web_credentials
|
173
|
-
@alerts
|
174
|
-
@users
|
175
|
-
@tags
|
170
|
+
@site_credentials = []
|
171
|
+
@shared_credentials = []
|
172
|
+
@web_credentials = []
|
173
|
+
@alerts = []
|
174
|
+
@users = []
|
175
|
+
@tags = []
|
176
176
|
end
|
177
177
|
|
178
178
|
# Returns the array of included scan target addresses.
|
@@ -231,23 +231,20 @@ module Nexpose
|
|
231
231
|
def is_dynamic?
|
232
232
|
!@discovery_config.nil?
|
233
233
|
end
|
234
|
+
alias dynamic? is_dynamic?
|
234
235
|
|
235
236
|
# Adds assets to this site by IP address range.
|
236
237
|
#
|
237
238
|
# @param [String] from Beginning IP address of a range.
|
238
239
|
# @param [String] to Ending IP address of a range.
|
239
240
|
def include_ip_range(from, to)
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
@included_scan_targets[:addresses] << IPRange.new(from, to)
|
248
|
-
rescue ArgumentError => e
|
249
|
-
raise "#{e.message} in given IP range"
|
250
|
-
end
|
241
|
+
from_ip = IPAddr.new(from)
|
242
|
+
to_ip = IPAddr.new(to)
|
243
|
+
(from_ip..to_ip)
|
244
|
+
raise 'Invalid IP range specified' if (from_ip..to_ip).to_a.size.zero?
|
245
|
+
@included_scan_targets[:addresses] << IPRange.new(from, to)
|
246
|
+
rescue ArgumentError => e
|
247
|
+
raise "#{e.message} in given IP range"
|
251
248
|
end
|
252
249
|
|
253
250
|
# Remove assets to this site by IP address range.
|
@@ -255,17 +252,13 @@ module Nexpose
|
|
255
252
|
# @param [String] from Beginning IP address of a range.
|
256
253
|
# @param [String] to Ending IP address of a range.
|
257
254
|
def remove_included_ip_range(from, to)
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
@included_scan_targets[:addresses].reject! { |t| t.eql? IPRange.new(from, to) }
|
266
|
-
rescue ArgumentError => e
|
267
|
-
raise "#{e.message} in given IP range"
|
268
|
-
end
|
255
|
+
from_ip = IPAddr.new(from)
|
256
|
+
to_ip = IPAddr.new(to)
|
257
|
+
(from_ip..to_ip)
|
258
|
+
raise 'Invalid IP range specified' if (from_ip..to_ip).to_a.size.zero?
|
259
|
+
@included_scan_targets[:addresses].reject! { |t| t.eql? IPRange.new(from, to) }
|
260
|
+
rescue ArgumentError => e
|
261
|
+
raise "#{e.message} in given IP range"
|
269
262
|
end
|
270
263
|
|
271
264
|
# Adds an asset to this site included scan targets, resolving whether an IP or hostname is
|
@@ -291,17 +284,13 @@ module Nexpose
|
|
291
284
|
# @param [String] from Beginning IP address of a range.
|
292
285
|
# @param [String] to Ending IP address of a range.
|
293
286
|
def exclude_ip_range(from, to)
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
@excluded_scan_targets[:addresses] << IPRange.new(from, to)
|
302
|
-
rescue ArgumentError => e
|
303
|
-
raise "#{e.message} in given IP range"
|
304
|
-
end
|
287
|
+
from_ip = IPAddr.new(from)
|
288
|
+
to_ip = IPAddr.new(to)
|
289
|
+
(from_ip..to_ip)
|
290
|
+
raise 'Invalid IP range specified' if (from_ip..to_ip).to_a.size.zero?
|
291
|
+
@excluded_scan_targets[:addresses] << IPRange.new(from, to)
|
292
|
+
rescue ArgumentError => e
|
293
|
+
raise "#{e.message} in given IP range"
|
305
294
|
end
|
306
295
|
|
307
296
|
# Remove assets from this site excluded scan targets by IP address range.
|
@@ -309,17 +298,13 @@ module Nexpose
|
|
309
298
|
# @param [String] from Beginning IP address of a range.
|
310
299
|
# @param [String] to Ending IP address of a range.
|
311
300
|
def remove_excluded_ip_range(from, to)
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
@excluded_scan_targets[:addresses].reject! { |t| t.eql? IPRange.new(from, to) }
|
320
|
-
rescue ArgumentError => e
|
321
|
-
raise "#{e.message} in given IP range"
|
322
|
-
end
|
301
|
+
from_ip = IPAddr.new(from)
|
302
|
+
to_ip = IPAddr.new(to)
|
303
|
+
(from_ip..to_ip)
|
304
|
+
raise 'Invalid IP range specified' if (from_ip..to_ip).to_a.size.zero?
|
305
|
+
@excluded_scan_targets[:addresses].reject! { |t| t.eql? IPRange.new(from, to) }
|
306
|
+
rescue ArgumentError => e
|
307
|
+
raise "#{e.message} in given IP range"
|
323
308
|
end
|
324
309
|
|
325
310
|
# Adds an asset to this site excluded scan targets, resolving whether an IP or hostname is
|
@@ -391,7 +376,7 @@ module Nexpose
|
|
391
376
|
raise 'Invalid user id. A user id must be a positive number and refer to an existing system user.'
|
392
377
|
end
|
393
378
|
|
394
|
-
@users << { id: user_id}
|
379
|
+
@users << { id: user_id }
|
395
380
|
end
|
396
381
|
|
397
382
|
def remove_user(user_id)
|
@@ -427,36 +412,29 @@ module Nexpose
|
|
427
412
|
end
|
428
413
|
|
429
414
|
def to_h
|
430
|
-
included_scan_targets = {
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
discovery_config: @discovery_config.to_h,
|
454
|
-
search_criteria: @search_criteria.to_h,
|
455
|
-
tags: (@tags || []).map{|tag| tag.to_h},
|
456
|
-
alerts: (@alerts || []).map {|alert| alert.to_h },
|
457
|
-
organization: @organization.to_h,
|
458
|
-
users: users
|
459
|
-
}
|
415
|
+
included_scan_targets = { addresses: @included_scan_targets[:addresses].compact,
|
416
|
+
asset_groups: @included_scan_targets[:asset_groups].compact }
|
417
|
+
excluded_scan_targets = { addresses: @excluded_scan_targets[:addresses].compact,
|
418
|
+
asset_groups: @excluded_scan_targets[:asset_groups].compact }
|
419
|
+
hash = { id: @id,
|
420
|
+
name: @name,
|
421
|
+
description: @description,
|
422
|
+
auto_engine_selection_enabled: @auto_engine_selection_enabled,
|
423
|
+
included_scan_targets: included_scan_targets,
|
424
|
+
excluded_scan_targets: excluded_scan_targets,
|
425
|
+
engine_id: @engine_id,
|
426
|
+
scan_template_id: @scan_template_id,
|
427
|
+
risk_factor: @risk_factor,
|
428
|
+
schedules: (@schedules || []).map(&:to_h),
|
429
|
+
shared_credentials: (@shared_credentials || []).map(&:to_h),
|
430
|
+
site_credentials: (@site_credentials || []).map(&:to_h),
|
431
|
+
web_credentials: (@web_credentials || []).map(&:to_h),
|
432
|
+
discovery_config: @discovery_config.to_h,
|
433
|
+
search_criteria: @search_criteria.to_h,
|
434
|
+
tags: (@tags || []).map(&:to_h),
|
435
|
+
alerts: (@alerts || []).map(&:to_h),
|
436
|
+
organization: @organization.to_h,
|
437
|
+
users: users }
|
460
438
|
# @TODO: Revisit this for 2.0.0 update
|
461
439
|
# Only pass in blackouts if they were actually specified (for backwards compatibility)
|
462
440
|
hash[:blackouts] = @blackouts.map(&:to_h) if @blackouts && @blackouts.any?
|
@@ -472,7 +450,7 @@ module Nexpose
|
|
472
450
|
# @return [Site] The requested site, if found.
|
473
451
|
#
|
474
452
|
def self.load(nsc, id)
|
475
|
-
uri
|
453
|
+
uri = "/api/2.1/site_configurations/#{id}"
|
476
454
|
resp = AJAX.get(nsc, uri, AJAX::CONTENT_TYPE::JSON)
|
477
455
|
hash = JSON.parse(resp, symbolize_names: true)
|
478
456
|
site = self.json_initializer(hash).deserialize(hash)
|
@@ -486,19 +464,19 @@ module Nexpose
|
|
486
464
|
site.excluded_scan_targets[:addresses] = []
|
487
465
|
excluded_addresses.each { |asset| site.exclude_asset(asset) }
|
488
466
|
|
489
|
-
site.organization
|
490
|
-
site.schedules
|
491
|
-
site.blackouts
|
492
|
-
site.site_credentials
|
493
|
-
site.shared_credentials = hash[:shared_credentials].map {|cred| Nexpose::SiteCredentials.new.object_from_hash(nsc,cred)}
|
494
|
-
site.discovery_config
|
495
|
-
site.search_criteria
|
496
|
-
site.alerts
|
497
|
-
site.tags
|
498
|
-
site.web_credentials = hash[:web_credentials].map {|
|
499
|
-
|
500
|
-
Nexpose::WebCredentials::Headers.new(
|
501
|
-
Nexpose::WebCredentials::HTMLForms.new(
|
467
|
+
site.organization = Organization.create(site.organization)
|
468
|
+
site.schedules = (hash[:schedules] || []).map { |schedule| Nexpose::Schedule.from_hash(schedule) }
|
469
|
+
site.blackouts = (hash[:blackouts] || []).map { |blackout| Nexpose::Blackout.from_hash(blackout) }
|
470
|
+
site.site_credentials = hash[:site_credentials].map { |cred| Nexpose::SiteCredentials.new.object_from_hash(nsc, cred) }
|
471
|
+
site.shared_credentials = hash[:shared_credentials].map { |cred| Nexpose::SiteCredentials.new.object_from_hash(nsc, cred) }
|
472
|
+
site.discovery_config = Nexpose::DiscoveryConnection.new.object_from_hash(nsc, hash[:discovery_config]) unless hash[:discovery_config].nil?
|
473
|
+
site.search_criteria = Nexpose::DiscoveryConnection::Criteria.parseHash(hash[:search_criteria]) unless hash[:search_criteria].nil?
|
474
|
+
site.alerts = Alert.load_alerts(hash[:alerts])
|
475
|
+
site.tags = Tag.load_tags(hash[:tags])
|
476
|
+
site.web_credentials = hash[:web_credentials].map { |web_cred| (
|
477
|
+
web_cred[:service] == Nexpose::WebCredentials::WebAppAuthType::HTTP_HEADER ?
|
478
|
+
Nexpose::WebCredentials::Headers.new(web_cred[:name], web_cred[:baseURL], web_cred[:soft403Pattern], web_cred[:id]).object_from_hash(nsc, web_cred) :
|
479
|
+
Nexpose::WebCredentials::HTMLForms.new(web_cred[:name], web_cred[:baseURL], web_cred[:loginURL], web_cred[:soft403Pattern], web_cred[:id]).object_from_hash(nsc, web_cred)) }
|
502
480
|
|
503
481
|
site
|
504
482
|
end
|
@@ -516,8 +494,8 @@ module Nexpose
|
|
516
494
|
# @return [Site] Site configuration loaded from a Nexpose console.
|
517
495
|
#
|
518
496
|
def self.copy(connection, id)
|
519
|
-
site
|
520
|
-
site.id
|
497
|
+
site = self.load(connection, id)
|
498
|
+
site.id = -1
|
521
499
|
site.name = "#{site.name} Copy"
|
522
500
|
site
|
523
501
|
end
|
@@ -536,14 +514,14 @@ module Nexpose
|
|
536
514
|
resp = AJAX.post(connection, '/api/2.1/site_configurations/', to_json, AJAX::CONTENT_TYPE::JSON)
|
537
515
|
@id = resp.to_i
|
538
516
|
else
|
539
|
-
|
517
|
+
AJAX.put(connection, "/api/2.1/site_configurations/#{@id}", to_json, AJAX::CONTENT_TYPE::JSON)
|
540
518
|
end
|
541
519
|
|
542
520
|
# Retrieve the scan engine and shared credentials and add them to the site configuration
|
543
|
-
site_config
|
544
|
-
@engine_id
|
521
|
+
site_config = Site.load(connection, @id)
|
522
|
+
@engine_id = site_config.engine_id
|
545
523
|
@shared_credentials = site_config.shared_credentials
|
546
|
-
@alerts
|
524
|
+
@alerts = site_config.alerts
|
547
525
|
|
548
526
|
@id
|
549
527
|
end
|
@@ -592,11 +570,11 @@ module Nexpose
|
|
592
570
|
# Constructor
|
593
571
|
# SiteSummary(id, name, description, riskfactor = 1)
|
594
572
|
def initialize(id, name, description = nil, risk_factor = 1.0, risk_score = 0.0)
|
595
|
-
@id
|
596
|
-
@name
|
573
|
+
@id = id
|
574
|
+
@name = name
|
597
575
|
@description = description
|
598
576
|
@risk_factor = risk_factor
|
599
|
-
@risk_score
|
577
|
+
@risk_score = risk_score
|
600
578
|
end
|
601
579
|
end
|
602
580
|
|
@@ -629,7 +607,7 @@ module Nexpose
|
|
629
607
|
xml.text = @host
|
630
608
|
xml
|
631
609
|
end
|
632
|
-
|
610
|
+
alias to_xml_elem as_xml
|
633
611
|
|
634
612
|
def to_xml
|
635
613
|
to_xml_elem.to_s
|
@@ -670,14 +648,14 @@ module Nexpose
|
|
670
648
|
# @return [IPRange] an IP address range of one or more addresses.
|
671
649
|
def initialize(from, to = nil)
|
672
650
|
@from = from
|
673
|
-
@to
|
651
|
+
@to = to unless from == to
|
674
652
|
|
675
653
|
return unless @to.nil?
|
676
654
|
|
677
655
|
range = IPAddr.new(@from.to_s).to_range
|
678
656
|
unless range.one?
|
679
657
|
@from = range.first.to_s
|
680
|
-
@to
|
658
|
+
@to = range.last.to_s
|
681
659
|
end
|
682
660
|
end
|
683
661
|
|
@@ -689,7 +667,7 @@ module Nexpose
|
|
689
667
|
def size
|
690
668
|
return 1 if @to.nil?
|
691
669
|
from = IPAddr.new(@from)
|
692
|
-
to
|
670
|
+
to = IPAddr.new(@to)
|
693
671
|
(from..to).to_a.size
|
694
672
|
end
|
695
673
|
|
@@ -697,10 +675,10 @@ module Nexpose
|
|
697
675
|
|
698
676
|
def <=>(other)
|
699
677
|
return 1 unless other.respond_to? :from
|
700
|
-
from
|
701
|
-
to
|
678
|
+
from = IPAddr.new(@from)
|
679
|
+
to = @to.nil? ? from : IPAddr.new(@to)
|
702
680
|
cf_from = IPAddr.new(other.from)
|
703
|
-
cf_to
|
681
|
+
cf_to = IPAddr.new(other.to.nil? ? other.from : other.to)
|
704
682
|
if cf_to < from
|
705
683
|
1
|
706
684
|
elsif to < cf_from
|
@@ -721,8 +699,8 @@ module Nexpose
|
|
721
699
|
|
722
700
|
def include?(single_ip)
|
723
701
|
return false unless single_ip.respond_to? :from
|
724
|
-
from
|
725
|
-
to
|
702
|
+
from = IPAddr.new(@from)
|
703
|
+
to = @to.nil? ? from : IPAddr.new(@to)
|
726
704
|
other = IPAddr.new(single_ip)
|
727
705
|
|
728
706
|
if other < from
|
@@ -743,7 +721,7 @@ module Nexpose
|
|
743
721
|
xml.add_attributes({ 'from' => @from, 'to' => @to })
|
744
722
|
xml
|
745
723
|
end
|
746
|
-
|
724
|
+
alias to_xml_elem as_xml
|
747
725
|
|
748
726
|
def to_xml
|
749
727
|
as_xml.to_s
|
@@ -49,7 +49,7 @@ module Nexpose
|
|
49
49
|
attr_accessor :use_windows_auth
|
50
50
|
# sid for oracle
|
51
51
|
attr_accessor :sid
|
52
|
-
#for ssh public key require pem format private key
|
52
|
+
# for ssh public key require pem format private key
|
53
53
|
attr_accessor :pem_format_private_key
|
54
54
|
# for snmp v1/v2
|
55
55
|
attr_accessor :community_name
|
@@ -71,14 +71,13 @@ module Nexpose
|
|
71
71
|
unless engine_id
|
72
72
|
engine_id = nsc.engines.detect { |e| e.name == 'Local scan engine' }.id
|
73
73
|
end
|
74
|
-
@port
|
74
|
+
@port = Credential::DEFAULT_PORTS[@service] if @port.nil?
|
75
75
|
parameters = _to_param(target, engine_id, @port, siteid)
|
76
76
|
parameters = JSON.generate(parameters)
|
77
|
-
resp
|
77
|
+
resp = JSON.parse(Nexpose::AJAX.post(nsc, '/data/credential/test', parameters, Nexpose::AJAX::CONTENT_TYPE::JSON))
|
78
78
|
resp['success'] == 'true'
|
79
79
|
end
|
80
80
|
|
81
|
-
|
82
81
|
def _to_param(target, engine_id, port, siteid)
|
83
82
|
{
|
84
83
|
dev: target,
|
@@ -100,17 +99,17 @@ module Nexpose
|
|
100
99
|
}
|
101
100
|
end
|
102
101
|
|
103
|
-
#Create a credential object using name, id, description, host and port
|
102
|
+
# Create a credential object using name, id, description, host and port
|
104
103
|
def self.for_service(name, id = -1, desc = nil, host = nil, port = nil, service = Credential::Service::CIFS)
|
105
|
-
cred
|
106
|
-
cred.name
|
107
|
-
cred.id
|
108
|
-
cred.enabled
|
109
|
-
cred.description
|
110
|
-
cred.host_restriction
|
111
|
-
cred.port_restriction
|
112
|
-
cred.service
|
113
|
-
cred.scope
|
104
|
+
cred = new
|
105
|
+
cred.name = name
|
106
|
+
cred.id = id.to_i
|
107
|
+
cred.enabled = true
|
108
|
+
cred.description = desc
|
109
|
+
cred.host_restriction = host
|
110
|
+
cred.port_restriction = port
|
111
|
+
cred.service = service
|
112
|
+
cred.scope = Credential::Scope::SITE_SPECIFIC
|
114
113
|
cred.permission_elevation_type = Credential::ElevationType::NONE
|
115
114
|
cred
|
116
115
|
end
|
@@ -123,7 +122,7 @@ module Nexpose
|
|
123
122
|
# @return [SiteCredential] The requested credential of site, if found.
|
124
123
|
#
|
125
124
|
def self.load(nsc, site_id, credential_id)
|
126
|
-
uri
|
125
|
+
uri = "/api/2.1/sites/#{site_id}/credentials/#{credential_id}"
|
127
126
|
resp = AJAX.get(nsc, uri, AJAX::CONTENT_TYPE::JSON)
|
128
127
|
hash = JSON.parse(resp, symbolize_names: true)
|
129
128
|
new.object_from_hash(nsc, hash)
|
@@ -187,8 +186,7 @@ module Nexpose
|
|
187
186
|
sid: sid,
|
188
187
|
pem_format_private_key: pem_format_private_key,
|
189
188
|
community_name: community_name,
|
190
|
-
scope: scope
|
191
|
-
}
|
189
|
+
scope: scope }
|
192
190
|
end
|
193
191
|
|
194
192
|
def ==(other)
|
data/lib/nexpose/tag.rb
CHANGED
@@ -8,13 +8,13 @@ module Nexpose
|
|
8
8
|
#
|
9
9
|
def tags
|
10
10
|
tag_summary = []
|
11
|
-
tags
|
11
|
+
tags = JSON.parse(AJAX.get(self, '/api/2.0/tags', AJAX::CONTENT_TYPE::JSON, { per_page: 2_147_483_647 }))
|
12
12
|
tags['resources'].each do |json|
|
13
13
|
tag_summary << TagSummary.parse(json)
|
14
14
|
end
|
15
15
|
tag_summary
|
16
16
|
end
|
17
|
-
|
17
|
+
alias list_tags tags
|
18
18
|
|
19
19
|
# Deletes a tag by ID
|
20
20
|
#
|
@@ -31,13 +31,13 @@ module Nexpose
|
|
31
31
|
#
|
32
32
|
def asset_tags(asset_id)
|
33
33
|
tag_summary = []
|
34
|
-
asset_tag
|
34
|
+
asset_tag = JSON.parse(AJAX.get(self, "/api/2.0/assets/#{asset_id}/tags", AJAX::CONTENT_TYPE::JSON, { per_page: 2_147_483_647 }))
|
35
35
|
asset_tag['resources'].select { |r| r['asset_ids'].find { |i| i == asset_id } }.each do |json|
|
36
36
|
tag_summary << TagSummary.parse(json)
|
37
37
|
end
|
38
38
|
tag_summary
|
39
39
|
end
|
40
|
-
|
40
|
+
alias list_asset_tags asset_tags
|
41
41
|
|
42
42
|
# Removes a tag from an asset
|
43
43
|
#
|
@@ -61,7 +61,7 @@ module Nexpose
|
|
61
61
|
end
|
62
62
|
tag_summary
|
63
63
|
end
|
64
|
-
|
64
|
+
alias list_site_tags site_tags
|
65
65
|
|
66
66
|
# Removes a tag from a site
|
67
67
|
#
|
@@ -85,8 +85,8 @@ module Nexpose
|
|
85
85
|
end
|
86
86
|
tag_summary
|
87
87
|
end
|
88
|
-
|
89
|
-
|
88
|
+
alias group_tags asset_group_tags
|
89
|
+
alias list_asset_group_tags asset_group_tags
|
90
90
|
|
91
91
|
# Removes a tag from an asset_group
|
92
92
|
#
|
@@ -96,7 +96,7 @@ module Nexpose
|
|
96
96
|
def remove_tag_from_asset_group(asset_group_id, tag_id)
|
97
97
|
AJAX.delete(self, "/api/2.0/asset_groups/#{asset_group_id}/tags/#{tag_id}")
|
98
98
|
end
|
99
|
-
|
99
|
+
alias remove_tag_from_group remove_tag_from_asset_group
|
100
100
|
|
101
101
|
# Returns the criticality value which takes precedent for an asset
|
102
102
|
#
|
@@ -123,7 +123,9 @@ module Nexpose
|
|
123
123
|
attr_accessor :type
|
124
124
|
|
125
125
|
def initialize(name, type, id)
|
126
|
-
@name
|
126
|
+
@name = name
|
127
|
+
@type = type
|
128
|
+
@id = id
|
127
129
|
end
|
128
130
|
|
129
131
|
def self.parse(json)
|
@@ -154,27 +156,27 @@ module Nexpose
|
|
154
156
|
# Criticality tag types
|
155
157
|
module Level
|
156
158
|
VERY_HIGH = 'Very High'
|
157
|
-
HIGH
|
158
|
-
MEDIUM
|
159
|
-
LOW
|
160
|
-
VERY_LOW
|
159
|
+
HIGH = 'High'
|
160
|
+
MEDIUM = 'Medium'
|
161
|
+
LOW = 'Low'
|
162
|
+
VERY_LOW = 'Very Low'
|
161
163
|
end
|
162
164
|
|
163
165
|
# Tag types
|
164
166
|
module Generic
|
165
|
-
CUSTOM
|
166
|
-
OWNER
|
167
|
-
LOCATION
|
167
|
+
CUSTOM = 'CUSTOM'
|
168
|
+
OWNER = 'OWNER'
|
169
|
+
LOCATION = 'LOCATION'
|
168
170
|
CRITICALITY = 'CRITICALITY'
|
169
171
|
end
|
170
172
|
|
171
173
|
module Color
|
172
|
-
BLUE
|
173
|
-
DEFAULT =
|
174
|
-
GREEN
|
175
|
-
ORANGE
|
176
|
-
PURPLE
|
177
|
-
RED
|
174
|
+
BLUE = '#496a77'
|
175
|
+
DEFAULT = '#f6f6f6'
|
176
|
+
GREEN = '#7d8a58'
|
177
|
+
ORANGE = '#de7200'
|
178
|
+
PURPLE = '#844f7d'
|
179
|
+
RED = '#a0392e'
|
178
180
|
end
|
179
181
|
end
|
180
182
|
|
@@ -198,26 +200,28 @@ module Nexpose
|
|
198
200
|
|
199
201
|
# Array containing Asset Group IDs to be associated with tag
|
200
202
|
attr_accessor :asset_group_ids
|
201
|
-
|
202
|
-
|
203
|
+
alias group_ids asset_group_ids
|
204
|
+
alias group_ids= asset_group_ids=
|
203
205
|
|
204
206
|
# A TagCriteria
|
205
207
|
attr_accessor :search_criteria
|
206
208
|
|
207
209
|
def initialize(name, type, id = -1)
|
208
|
-
@name
|
210
|
+
@name = name
|
211
|
+
@type = type
|
212
|
+
@id = id
|
209
213
|
@source = 'nexpose-client'
|
210
|
-
@color
|
214
|
+
@color = @type == Type::Generic::CUSTOM ? Type::Color::DEFAULT : nil
|
211
215
|
end
|
212
216
|
|
213
217
|
# Set the color but validate it
|
214
218
|
def color=(hex)
|
215
|
-
valid_colors = Type::Color
|
219
|
+
valid_colors = Type::Color.constants.map { |c| Type::Color.const_get(c) }
|
216
220
|
unless hex.nil? || valid_colors.include?(hex.to_s.downcase)
|
217
221
|
raise ArgumentError, "Unable to set color to an invalid color.\nUse one of #{valid_colors}"
|
218
|
-
end
|
222
|
+
end
|
219
223
|
|
220
|
-
@color = hex
|
224
|
+
@color = hex
|
221
225
|
end
|
222
226
|
|
223
227
|
# Create list of tag objects from hash
|
@@ -233,12 +237,12 @@ module Nexpose
|
|
233
237
|
# Create tag object from hash
|
234
238
|
def self.create(hash)
|
235
239
|
attributes = hash[:attributes]
|
236
|
-
color
|
237
|
-
color
|
238
|
-
source
|
239
|
-
source
|
240
|
-
tag
|
241
|
-
tag.color
|
240
|
+
color = attributes.find { |attr| attr[:tag_attribute_name] == 'COLOR' }
|
241
|
+
color = color[:tag_attribute_value] if color
|
242
|
+
source = attributes.find { |attr| attr[:tag_attribute_name] == 'SOURCE' }
|
243
|
+
source = source[:tag_attribute_value] if source
|
244
|
+
tag = Tag.new(hash[:tag_name], hash[:tag_type], hash[:tag_id])
|
245
|
+
tag.color = color
|
242
246
|
tag.source = source
|
243
247
|
tag
|
244
248
|
end
|
@@ -248,15 +252,9 @@ module Nexpose
|
|
248
252
|
tag_id: id,
|
249
253
|
tag_name: name,
|
250
254
|
tag_type: type,
|
251
|
-
attributes:[
|
252
|
-
{
|
253
|
-
|
254
|
-
tag_attribute_value: color
|
255
|
-
},
|
256
|
-
{
|
257
|
-
tag_attribute_name: "SOURCE",
|
258
|
-
tag_attribute_value: source
|
259
|
-
}
|
255
|
+
attributes: [
|
256
|
+
{ tag_attribute_name: 'COLOR', tag_attribute_value: color },
|
257
|
+
{ tag_attribute_name: 'SOURCE', tag_attribute_value: source }
|
260
258
|
]
|
261
259
|
}
|
262
260
|
end
|
@@ -289,18 +287,15 @@ module Nexpose
|
|
289
287
|
end
|
290
288
|
|
291
289
|
def to_json
|
292
|
-
json = {
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
'search_criteria' => @search_criteria ? @search_criteria.to_h : nil
|
302
|
-
}
|
303
|
-
}
|
290
|
+
json = { 'tag_name' => @name,
|
291
|
+
'tag_type' => @type,
|
292
|
+
'tag_id' => @id,
|
293
|
+
'attributes' => [{ 'tag_attribute_name' => 'SOURCE',
|
294
|
+
'tag_attribute_value' => @source }],
|
295
|
+
'tag_config' => { 'site_ids' => @site_ids,
|
296
|
+
'tag_associated_asset_ids' => @associated_asset_ids,
|
297
|
+
'asset_group_ids' => @asset_group_ids,
|
298
|
+
'search_criteria' => @search_criteria ? @search_criteria.to_h : nil } }
|
304
299
|
if @type == Type::Generic::CUSTOM
|
305
300
|
json['attributes'] << { 'tag_attribute_name' => 'COLOR', 'tag_attribute_value' => @color }
|
306
301
|
end
|
@@ -316,25 +311,23 @@ module Nexpose
|
|
316
311
|
end
|
317
312
|
|
318
313
|
def self.parse(json)
|
319
|
-
color
|
320
|
-
color
|
321
|
-
source
|
322
|
-
source
|
323
|
-
tag
|
324
|
-
tag.color
|
325
|
-
tag.source
|
314
|
+
color = json['attributes'].find { |attr| attr['tag_attribute_name'] == 'COLOR' }
|
315
|
+
color = color['tag_attribute_value'] if color
|
316
|
+
source = json['attributes'].find { |attr| attr['tag_attribute_name'] == 'SOURCE' }
|
317
|
+
source = source['tag_attribute_value'] if source
|
318
|
+
tag = Tag.new(json['tag_name'], json['tag_type'], json['tag_id'])
|
319
|
+
tag.color = color
|
320
|
+
tag.source = source
|
326
321
|
tag.asset_ids = json['asset_ids']
|
327
322
|
if json['tag_config']
|
328
|
-
tag.site_ids
|
323
|
+
tag.site_ids = json['tag_config']['site_ids']
|
329
324
|
tag.associated_asset_ids = json['tag_config']['tag_associated_asset_ids']
|
330
|
-
tag.asset_group_ids
|
331
|
-
criteria
|
332
|
-
tag.search_criteria
|
325
|
+
tag.asset_group_ids = json['tag_config']['asset_group_ids']
|
326
|
+
criteria = json['tag_config']['search_criteria']
|
327
|
+
tag.search_criteria = criteria ? Criteria.parse(criteria) : nil
|
333
328
|
end
|
334
329
|
modifier = json['attributes'].find { |attr| attr['tag_attribute_name'] == 'RISK_MODIFIER' }
|
335
|
-
if modifier
|
336
|
-
tag.risk_modifier = modifier['tag_attribute_value'].to_i
|
337
|
-
end
|
330
|
+
tag.risk_modifier = modifier['tag_attribute_value'].to_i if modifier
|
338
331
|
tag
|
339
332
|
end
|
340
333
|
|
@@ -346,9 +339,9 @@ module Nexpose
|
|
346
339
|
#
|
347
340
|
def add_to_asset(connection, asset_id)
|
348
341
|
params = to_json_for_add
|
349
|
-
url
|
350
|
-
uri
|
351
|
-
@id
|
342
|
+
url = "/api/2.0/assets/#{asset_id}/tags"
|
343
|
+
uri = AJAX.post(connection, url, params, AJAX::CONTENT_TYPE::JSON)
|
344
|
+
@id = uri.split('/').last.to_i
|
352
345
|
end
|
353
346
|
|
354
347
|
# Adds a tag to a site
|
@@ -359,9 +352,9 @@ module Nexpose
|
|
359
352
|
#
|
360
353
|
def add_to_site(connection, site_id)
|
361
354
|
params = to_json_for_add
|
362
|
-
url
|
363
|
-
uri
|
364
|
-
@id
|
355
|
+
url = "/api/2.0/sites/#{site_id}/tags"
|
356
|
+
uri = AJAX.post(connection, url, params, AJAX::CONTENT_TYPE::JSON)
|
357
|
+
@id = uri.split('/').last.to_i
|
365
358
|
end
|
366
359
|
|
367
360
|
# Adds a tag to an asset group
|
@@ -372,11 +365,11 @@ module Nexpose
|
|
372
365
|
#
|
373
366
|
def add_to_group(connection, group_id)
|
374
367
|
params = to_json_for_add
|
375
|
-
url
|
376
|
-
uri
|
377
|
-
@id
|
368
|
+
url = "/api/2.0/asset_groups/#{group_id}/tags"
|
369
|
+
uri = AJAX.post(connection, url, params, AJAX::CONTENT_TYPE::JSON)
|
370
|
+
@id = uri.split('/').last.to_i
|
378
371
|
end
|
379
|
-
|
372
|
+
alias add_to_asset_group add_to_group
|
380
373
|
|
381
374
|
private
|
382
375
|
|