nexpose_servicenow 0.4.24 → 0.5.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/README.md +11 -3
- data/lib/nexpose_servicenow.rb +67 -58
- data/lib/nexpose_servicenow/arg_parser.rb +149 -51
- data/lib/nexpose_servicenow/chunker.rb +19 -14
- data/lib/nexpose_servicenow/historical_data.rb +179 -65
- data/lib/nexpose_servicenow/nexpose_helper.rb +75 -53
- data/lib/nexpose_servicenow/queries.rb +145 -34
- data/lib/nexpose_servicenow/version.rb +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f3da5fa2194d025ab5192815f682a09a94583be
|
4
|
+
data.tar.gz: 94e1f6a2c0976fba3215185d62a2f0a03edcb5c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c6223fa14d6e6b0221e6176f5a4b79c4e9816dc2350592b68262cc94a98cf2cdf26d3bc647f699102c20954f9120fa12fdb1d0d4aa041a9c8cda75748036322
|
7
|
+
data.tar.gz: b5f07c1718b8cf959b932d6d76192c8ccd2a71b30ec70805334ab117f2e4f3b0e373ac2c3e876dced59f2e2d7f1dabc427568dd547c854cb636f6700c2b1fb2b
|
data/README.md
CHANGED
@@ -1,14 +1,22 @@
|
|
1
1
|
# NexposeServicenow
|
2
2
|
|
3
3
|
## Installation
|
4
|
+
The gem may installed via the following command from the RubyGems repository:
|
4
5
|
|
5
|
-
gem install nexpose_servicenow
|
6
|
+
`gem install nexpose_servicenow`
|
6
7
|
|
7
8
|
## Usage
|
9
|
+
The gem is called by the ServiceNow console when a vulnerability integration executes.
|
8
10
|
|
9
|
-
|
11
|
+
Alternatively, it is also possible to call the following to see a list of parameters:
|
12
|
+
`nexpose_servicenow -h`
|
10
13
|
|
11
|
-
|
14
|
+
|
15
|
+
## Support
|
16
|
+
Please contact the following address for support queries:
|
17
|
+
[support@rapid7.com](support@rapid7.com)
|
18
|
+
|
19
|
+
Please attach both the gem logs and relevant snippets from the agent logs.
|
12
20
|
|
13
21
|
## License
|
14
22
|
|
data/lib/nexpose_servicenow.rb
CHANGED
@@ -8,31 +8,22 @@ require 'nexpose_servicenow/arg_parser'
|
|
8
8
|
require 'nexpose_servicenow/chunker'
|
9
9
|
require 'nexpose_servicenow/nx_logger'
|
10
10
|
require 'nexpose_servicenow/historical_data'
|
11
|
-
require
|
11
|
+
require 'nexpose_servicenow/version'
|
12
12
|
|
13
13
|
module NexposeServiceNow
|
14
14
|
class Main
|
15
15
|
def self.start(args)
|
16
16
|
options = ArgParser.parse(args)
|
17
17
|
|
18
|
-
log = setup_logging(options)
|
19
|
-
|
20
|
-
censored_options = options.dup
|
21
|
-
censored_options[:nexpose_username] = "*****"
|
22
|
-
censored_options[:nexpose_password] = "*****"
|
23
|
-
log.log_message("Options: #{censored_options}")
|
18
|
+
@log = setup_logging(options)
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
20
|
+
censored_options = options.dup
|
21
|
+
censored_options[:nexpose_username] = '*****'
|
22
|
+
censored_options[:nexpose_password] = '*****'
|
23
|
+
@log.log_message("Options: #{censored_options}")
|
30
24
|
|
31
|
-
|
32
|
-
|
33
|
-
options[:nexpose_ids] = get_nexpose_helper(options).all_sites.sort
|
34
|
-
options[:nexpose_ids].map! { |i| i.to_s }
|
35
|
-
end
|
25
|
+
options[:nexpose_ids] = get_collection_ids(options)
|
26
|
+
options[:start_time] = Time.new().strftime('%Y-%m-%m %H:%M:%S')
|
36
27
|
|
37
28
|
report_details = NexposeHelper.get_report_names(options[:query],
|
38
29
|
options[:nexpose_ids])
|
@@ -41,13 +32,21 @@ module NexposeServiceNow
|
|
41
32
|
options[:output_dir])
|
42
33
|
end
|
43
34
|
|
44
|
-
|
45
|
-
create_report(report_details, options)
|
35
|
+
update_delta_files(options) if options[:mode] == 'latest_scans'
|
46
36
|
|
47
|
-
|
37
|
+
create_report(report_details, options)
|
38
|
+
|
39
|
+
@log.log_message("Initialising #{options[:mode]} mode")
|
48
40
|
self.send("#{options[:mode]}_mode", report_details, options)
|
49
41
|
end
|
50
42
|
|
43
|
+
def self.get_historical_data(options)
|
44
|
+
HistoricalData.new(options[:output_dir],
|
45
|
+
options[:nexpose_ids],
|
46
|
+
options[:id_type],
|
47
|
+
options[:start_time])
|
48
|
+
end
|
49
|
+
|
51
50
|
def self.get_nexpose_helper(options)
|
52
51
|
NexposeHelper.new(options[:nexpose_url],
|
53
52
|
options[:nexpose_port],
|
@@ -55,6 +54,15 @@ module NexposeServiceNow
|
|
55
54
|
options[:nexpose_password])
|
56
55
|
end
|
57
56
|
|
57
|
+
# Retrieves list of all IDs if the user has chosen to import each group
|
58
|
+
def self.get_collection_ids(options)
|
59
|
+
return options[:nexpose_ids] if options[:nexpose_ids].first.to_s != '0'
|
60
|
+
|
61
|
+
@log.log_error_message("Retrieving array of all #{options[:id_type]} IDs")
|
62
|
+
helper = get_nexpose_helper(options)
|
63
|
+
helper.collection_ids(options[:id_type]).map(&:to_s)
|
64
|
+
end
|
65
|
+
|
58
66
|
def self.setup_logging(options)
|
59
67
|
log = NexposeServiceNow::NxLogger.instance
|
60
68
|
log.setup_statistics_collection(NexposeServiceNow::VENDOR,
|
@@ -66,43 +74,42 @@ module NexposeServiceNow
|
|
66
74
|
log
|
67
75
|
end
|
68
76
|
|
69
|
-
#Merges in the details from the last time the
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
historical_data = HistoricalData.new(options)
|
74
|
-
historical_data.update_last_scan_data
|
75
|
-
|
77
|
+
# Merges in the details from the last time the integration ran reports.
|
78
|
+
def self.update_delta_files(options)
|
79
|
+
historical_data = get_historical_data(options)
|
80
|
+
historical_data.update_delta_file
|
76
81
|
historical_data.save_vuln_timestamp(filter_sites(options))
|
77
82
|
end
|
78
83
|
|
79
|
-
#Create a report if explicitly required or else an existing
|
80
|
-
#report file isn't found
|
84
|
+
# Create a report if explicitly required or else an existing
|
85
|
+
# report file isn't found
|
81
86
|
def self.create_report(report_details, options)
|
82
|
-
|
87
|
+
if options[:mode].start_with? 'update_' or
|
88
|
+
(options[:mode] == 'latest_scans' && options[:id_type] != :site)
|
89
|
+
return
|
90
|
+
end
|
83
91
|
|
84
92
|
unless options[:gen_report]
|
85
|
-
#If any file is missing, perform all queries
|
86
|
-
return if report_details.all? { |f| File.exists?
|
93
|
+
# If any file is missing, perform all queries
|
94
|
+
return if report_details.all? { |f| File.exists? f[:report_name] }
|
87
95
|
end
|
88
96
|
|
89
97
|
credentials = %i{nexpose_username nexpose_password}
|
90
|
-
if credentials.any? { |cred| options[cred].to_s ==
|
91
|
-
log
|
92
|
-
log.log_error_message "Nexpose credentials necessary but not supplied."
|
98
|
+
if credentials.any? { |cred| options[cred].to_s == '' }
|
99
|
+
@log.log_error_message 'Nexpose credentials necessary but not supplied.'
|
93
100
|
exit -1
|
94
101
|
end
|
95
102
|
|
96
103
|
#Filter it down to sites which actively need queried
|
97
104
|
sites_to_scan = filter_sites(options)
|
98
105
|
nexpose_helper = get_nexpose_helper(options)
|
99
|
-
hist_data =
|
106
|
+
hist_data = get_historical_data(options)
|
100
107
|
vuln_query = options[:query].to_s.start_with? 'vulnerabili'
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
query_options = { last_scans: hist_data.last_scan_ids(sites_to_scan) }
|
108
|
+
|
109
|
+
delta_values = hist_data.stored_delta_values(sites_to_scan)
|
110
|
+
query_options = { delta_values: delta_values }
|
105
111
|
query_options[:vuln_query_date] = hist_data.last_vuln_run if vuln_query
|
112
|
+
query_options[:filters] = options[:filters]
|
106
113
|
|
107
114
|
filename = nexpose_helper.create_report(options[:query],
|
108
115
|
sites_to_scan,
|
@@ -110,8 +117,8 @@ module NexposeServiceNow
|
|
110
117
|
options[:output_dir],
|
111
118
|
query_options)
|
112
119
|
|
113
|
-
#A single String may be returned or an Array of Strings
|
114
|
-
if filename.class.to_s ==
|
120
|
+
# A single String may be returned or an Array of Strings
|
121
|
+
if filename.class.to_s == 'Array'
|
115
122
|
filename.map! { |f| File.expand_path(options[:output_dir], f) }
|
116
123
|
return filename.join("\n")
|
117
124
|
end
|
@@ -120,8 +127,8 @@ module NexposeServiceNow
|
|
120
127
|
end
|
121
128
|
|
122
129
|
def self.filter_sites(options)
|
123
|
-
#These queries always run to make sure certain data is up to date
|
124
|
-
exceptions =
|
130
|
+
# These queries always run to make sure certain data is up to date
|
131
|
+
exceptions = %w(vulnerabili asset_groups sites tags)
|
125
132
|
if exceptions.any? { |e| options[:query].to_s.start_with? e }
|
126
133
|
return options[:nexpose_ids]
|
127
134
|
end
|
@@ -132,28 +139,30 @@ module NexposeServiceNow
|
|
132
139
|
return options[:nexpose_ids]
|
133
140
|
end
|
134
141
|
|
135
|
-
historical_data =
|
142
|
+
historical_data = get_historical_data(options)
|
136
143
|
imported_sites_only = options[:query].to_s.eql? 'vulnerable_old_items'
|
137
|
-
sites_to_scan = historical_data.
|
144
|
+
sites_to_scan = historical_data.collections_to_import(imported_sites_only)
|
138
145
|
|
139
146
|
return sites_to_scan unless (sites_to_scan.nil? || sites_to_scan.empty?)
|
140
147
|
|
141
|
-
log
|
142
|
-
log.log_message "
|
143
|
-
log.log_message "Query requested was: #{options[:query]}."
|
148
|
+
@log.log_message "Sites #{options[:nexpose_ids]} are up to date."
|
149
|
+
@log.log_message "Query requested was: #{options[:query]}."
|
144
150
|
exit 0
|
145
151
|
end
|
146
152
|
|
147
|
-
#Print the chunk info
|
153
|
+
# Print the chunk info
|
148
154
|
def self.chunk_info_mode(report_details, options)
|
149
155
|
filtered_sites = filter_sites(options)
|
150
|
-
report_details = report_details.select
|
156
|
+
report_details = report_details.select do |d|
|
157
|
+
d[:id] == -1 or filtered_sites.include? d[:id]
|
158
|
+
end
|
151
159
|
chunker = Chunker.new(report_details, options[:row_limit])
|
152
160
|
|
153
|
-
|
161
|
+
# TODO: Check why filtered_sites are passed in here
|
162
|
+
puts chunker.preprocess
|
154
163
|
end
|
155
164
|
|
156
|
-
#Prints a chunk of CSV to the console
|
165
|
+
# Prints a chunk of CSV to the console
|
157
166
|
def self.get_chunk_mode(report_details, options)
|
158
167
|
#Get the byte offset and length
|
159
168
|
chunker = Chunker.new(report_details, options[:row_limit])
|
@@ -165,28 +174,28 @@ module NexposeServiceNow
|
|
165
174
|
end
|
166
175
|
|
167
176
|
def self.latest_scans_mode(report_details, options)
|
168
|
-
historical_data =
|
177
|
+
historical_data = get_historical_data(options)
|
169
178
|
puts historical_data.filter_report
|
170
179
|
end
|
171
180
|
|
172
181
|
def self.remove_last_scan_mode(report_details, options)
|
173
|
-
historical_data =
|
182
|
+
historical_data = get_historical_data(options)
|
174
183
|
historical_data.remove_last_scan_data
|
175
184
|
end
|
176
185
|
|
177
186
|
def self.update_last_scan_mode(report_details, options)
|
178
|
-
historical_data =
|
187
|
+
historical_data = get_historical_data(options)
|
179
188
|
historical_data.set_last_scan(options[:nexpose_ids].first,
|
180
189
|
options[:last_scan_data])
|
181
190
|
end
|
182
191
|
|
183
192
|
def self.remove_last_vuln_mode(report_details, options)
|
184
|
-
historical_data =
|
193
|
+
historical_data = get_historical_data(options)
|
185
194
|
historical_data.remove_last_vuln_data
|
186
195
|
end
|
187
196
|
|
188
197
|
def self.update_last_vuln_mode(report_details, options)
|
189
|
-
historical_data =
|
198
|
+
historical_data = get_historical_data(options)
|
190
199
|
historical_data.set_last_vuln(options[:last_scan_data],
|
191
200
|
options[:nexpose_ids])
|
192
201
|
end
|
@@ -1,119 +1,211 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'json'
|
3
|
+
require 'time'
|
3
4
|
require_relative './queries'
|
4
5
|
require_relative './nx_logger'
|
5
6
|
|
6
7
|
module NexposeServiceNow
|
7
8
|
class ArgParser
|
8
|
-
NX_ID_TYPES = %i[site
|
9
|
+
NX_ID_TYPES = %i[site asset_group]
|
9
10
|
MODES = %i[chunk_info get_chunk latest_scans
|
10
11
|
remove_last_scan update_last_scan
|
11
12
|
remove_last_vuln update_last_vuln]
|
12
13
|
|
13
14
|
QUERY_NAMES = Queries.methods(false)
|
14
|
-
|
15
|
-
QUERY_ALIASES = { 'devices' => 'cmdb_ci_outofband_device',
|
16
|
-
'vuln_items' => 'sn_vul_vulnerable_item',
|
17
|
-
'vuln_entries' => 'sn_vul_third_party_entry' }
|
18
|
-
|
15
|
+
|
19
16
|
def self.parse(args)
|
20
17
|
options = Hash.new
|
21
18
|
|
19
|
+
log = NexposeServiceNow::NxLogger.instance
|
20
|
+
log.log_message 'Parsing options.'
|
21
|
+
|
22
22
|
opt_parser = OptionParser.new do |opts|
|
23
|
-
opts.banner =
|
23
|
+
opts.banner = 'Usage: example.rb [options]'
|
24
24
|
|
25
|
-
opts.on(
|
26
|
-
|
25
|
+
opts.on('-o', '--output-dir DIRECTORY',
|
26
|
+
'Directory in which to save reports') do |output_dir|
|
27
27
|
options[:output_dir] = output_dir
|
28
28
|
end
|
29
29
|
|
30
|
-
opts.on(
|
30
|
+
opts.on('-m', '--mode MODE',
|
31
31
|
"Mode for program output. (#{MODES.join(', ')})") do |mode|
|
32
32
|
options[:mode] = mode
|
33
33
|
end
|
34
34
|
|
35
|
-
opts.on(
|
36
|
-
|
35
|
+
opts.on('-g', '--generate-report BOOLEAN',
|
36
|
+
'True to generate and download new report') do |gen|
|
37
37
|
char = gen.downcase[0]
|
38
|
-
options[:gen_report] =
|
38
|
+
options[:gen_report] = %w(y t).any? { |c| c == char }
|
39
39
|
end
|
40
40
|
|
41
|
-
opts.separator
|
42
|
-
opts.separator
|
41
|
+
opts.separator ''
|
42
|
+
opts.separator 'Query options:'
|
43
43
|
|
44
|
-
opts.on(
|
44
|
+
opts.on('-q', '--query QUERY', QUERY_NAMES,
|
45
45
|
"Select query (#{QUERY_NAMES.join(', ')})") do |query|
|
46
46
|
options[:query] = query
|
47
47
|
end
|
48
48
|
|
49
|
-
opts.on(
|
49
|
+
opts.on('-t', '--type TYPE', NX_ID_TYPES,
|
50
50
|
"Select type (#{NX_ID_TYPES.join(', ')})") do |type|
|
51
51
|
options[:id_type] = type
|
52
52
|
end
|
53
53
|
|
54
|
-
opts.on(
|
55
|
-
|
54
|
+
opts.on('-i', '--items x,y,z', Array,
|
55
|
+
'IDs of the nexpose items to scan') do |items|
|
56
56
|
options[:nexpose_ids] = items
|
57
57
|
end
|
58
58
|
|
59
|
-
opts.separator
|
60
|
-
opts.separator
|
59
|
+
opts.separator ''
|
60
|
+
opts.separator 'Nexpose options:'
|
61
61
|
|
62
|
-
opts.on(
|
63
|
-
|
62
|
+
opts.on('-n', '--nexpose-address URL',
|
63
|
+
'URL of the Nexpose server') do |url|
|
64
64
|
port = url.slice!(/:(\d+)$/)
|
65
65
|
port.slice! ':' unless port.nil?
|
66
66
|
|
67
|
-
url.slice!
|
67
|
+
url.slice! 'https://'
|
68
68
|
options[:nexpose_url] = url
|
69
69
|
options[:nexpose_port] = port || '3780'
|
70
|
-
@full_url = options[:nexpose_url] + ':' + options[:nexpose_port]
|
71
70
|
end
|
72
71
|
|
73
|
-
opts.on(
|
74
|
-
|
72
|
+
opts.on('-u', '--user USER',
|
73
|
+
'Username for Nexpose console') do |username|
|
75
74
|
options[:nexpose_username] = username
|
76
75
|
end
|
77
76
|
|
78
|
-
opts.on(
|
79
|
-
|
77
|
+
opts.on('-p', '--password PASSWORD',
|
78
|
+
'Password for the Nexpose user') do |password|
|
80
79
|
options[:nexpose_password] = password
|
81
80
|
end
|
82
81
|
|
83
|
-
opts.separator
|
84
|
-
opts.separator
|
82
|
+
opts.separator ''
|
83
|
+
opts.separator 'Chunk info mode options:'
|
85
84
|
|
86
|
-
opts.on(
|
87
|
-
|
85
|
+
opts.on('-r', '--row-limit LIMIT',
|
86
|
+
'Maximum number of rows per chunk (including header).') do |limit|
|
88
87
|
options[:row_limit] = limit.to_i
|
89
88
|
options[:row_limit] = 9_999_999 if options[:row_limit] <= 0
|
90
89
|
end
|
91
90
|
|
92
|
-
opts.separator
|
93
|
-
opts.separator
|
91
|
+
opts.separator ''
|
92
|
+
opts.separator 'Get chunk mode options:'
|
94
93
|
|
95
|
-
opts.on(
|
96
|
-
|
94
|
+
opts.on('-s', '--start START',
|
95
|
+
'The chunk starting offset.') do |start|
|
97
96
|
options[:chunk_start] = start.to_i
|
98
97
|
end
|
99
98
|
|
100
|
-
opts.on(
|
101
|
-
|
99
|
+
opts.on('-l', '--length LENGTH',
|
100
|
+
'The chunk length.') do |length|
|
102
101
|
options[:chunk_length] = length.to_i
|
103
102
|
end
|
104
103
|
|
105
|
-
opts.separator
|
106
|
-
opts.separator
|
104
|
+
opts.separator ''
|
105
|
+
opts.separator 'Filter options:'
|
106
|
+
|
107
|
+
=begin
|
108
|
+
# CVE filter is not currently supported.
|
109
|
+
opts.on('-v', '--vuln-identifier CVE',
|
110
|
+
'The CVE values for which to filter.') do |data|
|
111
|
+
# A value of 'none' means the user has left field blank
|
112
|
+
if data.to_s.downcase != 'none'
|
113
|
+
data = data.to_s.sub(' ', '').split(',')
|
114
|
+
|
115
|
+
invalid_cve = data.select { |f| (f =~ /(CVE-)?\d{4}-\d+/) == nil }
|
116
|
+
unless invalid_cve.empty?
|
117
|
+
error = "Invalid CVEs applied: #{invalid_cve}"
|
118
|
+
puts error
|
119
|
+
log.log_message error
|
120
|
+
exit -1
|
121
|
+
end
|
122
|
+
|
123
|
+
data = data.map do |c|
|
124
|
+
if c.start_with? 'CVE-'
|
125
|
+
c
|
126
|
+
else
|
127
|
+
"CVE-#{c}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
else
|
131
|
+
data = nil
|
132
|
+
end
|
133
|
+
|
134
|
+
options[:filters] ||= {}
|
135
|
+
options[:filters][:cve] = data
|
136
|
+
end
|
137
|
+
=end
|
138
|
+
opts.on('-c', '--cvss-score CVSS',
|
139
|
+
'The minimum CVSS score to import') do |data|
|
140
|
+
|
141
|
+
cvss_range = data.split('~')
|
142
|
+
|
143
|
+
if cvss_range.count != 2
|
144
|
+
error = "Expected two CVSS scores. Received #{cvss_range.count}"
|
145
|
+
puts error
|
146
|
+
log.log_message error
|
147
|
+
exit -1
|
148
|
+
end
|
149
|
+
|
150
|
+
cvss_range.each do |cvss|
|
151
|
+
next if cvss.to_s =~ /^0*(10(\.0+)?|\d(\.\d+)?)?$/
|
152
|
+
error = "Invalid CVSS score supplied: #{cvss}. Exiting"
|
153
|
+
puts error
|
154
|
+
log.log_message error
|
155
|
+
exit -1
|
156
|
+
end
|
157
|
+
|
158
|
+
options[:filters] ||= {}
|
159
|
+
options[:filters][:cvss] = cvss_range
|
160
|
+
end
|
107
161
|
|
108
|
-
opts.on(
|
109
|
-
|
162
|
+
opts.on('-d', '--date DATE',
|
163
|
+
'The minimum date for each vulnerability instance.') do |date|
|
164
|
+
# Date should be in format 'YYYY-MM-DD~YYYY-MM-DD'
|
165
|
+
dates = date.to_s.split('~')
|
166
|
+
|
167
|
+
if dates.count != 2
|
168
|
+
error = "Expected two dates. Received #{dates.count}"
|
169
|
+
puts error
|
170
|
+
log.log_message error
|
171
|
+
exit -1
|
172
|
+
end
|
173
|
+
|
174
|
+
# Add the dates
|
175
|
+
dates[0] = dates[0] + ' 00:00:00'
|
176
|
+
dates[1] = dates[1] + ' 23:59:59'
|
177
|
+
|
178
|
+
# Check for valid dates and placeholders
|
179
|
+
dates.map! do |d|
|
180
|
+
if d =~ /Y{4}-M{1,2}-D{1,2}/i
|
181
|
+
nil
|
182
|
+
elsif d =~ /\d{4}-\d{1,2}-\d{1,2}/
|
183
|
+
d
|
184
|
+
else
|
185
|
+
error = "Invalid date supplied: #{d}. Exiting."
|
186
|
+
puts error
|
187
|
+
log.log_message error
|
188
|
+
exit -1
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
options[:filters] ||= {}
|
193
|
+
options[:filters][:date] = dates
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
opts.separator ''
|
198
|
+
opts.separator 'Last scan file modification options:'
|
199
|
+
|
200
|
+
opts.on('-e', '--errata DATA',
|
201
|
+
'Date or scan ID to be inserted in last scan file.') do |data|
|
110
202
|
options[:last_scan_data] = data
|
111
203
|
end
|
112
204
|
|
113
|
-
opts.separator
|
114
|
-
opts.separator
|
205
|
+
opts.separator ''
|
206
|
+
opts.separator 'Common options:'
|
115
207
|
|
116
|
-
opts.on_tail(
|
208
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
117
209
|
puts opts
|
118
210
|
exit
|
119
211
|
end
|
@@ -125,21 +217,27 @@ module NexposeServiceNow
|
|
125
217
|
options
|
126
218
|
end
|
127
219
|
|
128
|
-
#TODO: Validate input depending on mode AND whether generating a report
|
129
|
-
# is required.
|
130
220
|
def self.validate_input(options)
|
131
221
|
#Insert defaults. Some are mode-specific.
|
132
222
|
options[:output_dir] ||= '.'
|
133
223
|
options[:row_limit] ||= 9_999_999
|
134
224
|
options[:id_type] ||= 'site'
|
135
225
|
options[:nexpose_ids] ||= []
|
226
|
+
options[:filters] ||= {}
|
136
227
|
|
137
228
|
options[:query] = 'latest_scans' if options[:mode] == 'latest_scans'
|
138
229
|
|
139
230
|
#By default, a report won't be generated if a chunk's being retrieved
|
140
231
|
if options[:gen_report].nil?
|
141
|
-
options[:gen_report] = options[:mode] ==
|
142
|
-
options[:mode] ==
|
232
|
+
options[:gen_report] = options[:mode] == 'chunk_info' ||
|
233
|
+
options[:mode] == 'latest_scans'
|
234
|
+
end
|
235
|
+
|
236
|
+
if options[:mode].to_s == ''
|
237
|
+
log = NexposeServiceNow::NxLogger.instance
|
238
|
+
log.log_message('Script was called without mode.')
|
239
|
+
puts 'No mode selected. Use -h to see command line options.'
|
240
|
+
exit -1
|
143
241
|
end
|
144
242
|
|
145
243
|
options
|
@@ -150,7 +248,7 @@ module NexposeServiceNow
|
|
150
248
|
return options if options[:gen_report] == false
|
151
249
|
|
152
250
|
log = NexposeServiceNow::NxLogger.instance
|
153
|
-
log.log_message
|
251
|
+
log.log_message 'Retrieving environment variables.'
|
154
252
|
|
155
253
|
# Retrieve environment variable settings
|
156
254
|
%i[url port username password].each do |setting|
|