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