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