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/vuln_def.rb
CHANGED
@@ -8,7 +8,7 @@ module Nexpose
|
|
8
8
|
# @return [Array[VulnerabilityDefinition]] Collection of vulnerability definitions.
|
9
9
|
#
|
10
10
|
def all_vulns
|
11
|
-
uri
|
11
|
+
uri = '/api/2.0/vulnerability_definitions'
|
12
12
|
resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, per_page: 2_147_483_647)
|
13
13
|
json = JSON.parse(resp, symbolize_names: true)
|
14
14
|
json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
|
@@ -20,7 +20,7 @@ module Nexpose
|
|
20
20
|
# @return [Array[VulnerabilityDefinition]] A list of vuln definitions which check the CVE.
|
21
21
|
#
|
22
22
|
def find_vulns_by_cve(cve)
|
23
|
-
uri
|
23
|
+
uri = '/api/2.0/vulnerability_definitions'
|
24
24
|
resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, cve: cve)
|
25
25
|
json = JSON.parse(resp, symbolize_names: true)
|
26
26
|
json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
|
@@ -40,7 +40,7 @@ module Nexpose
|
|
40
40
|
# check the vulnerability.
|
41
41
|
#
|
42
42
|
def find_vulns_by_ref(source, id)
|
43
|
-
uri
|
43
|
+
uri = '/api/2.0/vulnerability_definitions'
|
44
44
|
resp = AJAX.get(self,
|
45
45
|
uri,
|
46
46
|
AJAX::CONTENT_TYPE::JSON,
|
@@ -62,10 +62,10 @@ module Nexpose
|
|
62
62
|
# the provided value.
|
63
63
|
#
|
64
64
|
def find_vulns_by_title(title, all_words = true)
|
65
|
-
uri
|
65
|
+
uri = '/api/2.0/vulnerability_definitions'
|
66
66
|
params = { title: title, all_words: all_words }
|
67
|
-
resp
|
68
|
-
json
|
67
|
+
resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, params)
|
68
|
+
json = JSON.parse(resp, symbolize_names: true)
|
69
69
|
json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
|
70
70
|
end
|
71
71
|
end
|
@@ -121,7 +121,7 @@ module Nexpose
|
|
121
121
|
# @return [VulnerabilityDefinition] The requested vulnerability definition, if found.
|
122
122
|
#
|
123
123
|
def self.load(nsc, id)
|
124
|
-
uri
|
124
|
+
uri = "/api/2.0/vulnerability_definitions/#{id}"
|
125
125
|
resp = AJAX.get(nsc, uri, AJAX::CONTENT_TYPE::JSON)
|
126
126
|
hash = JSON.parse(resp, symbolize_names: true)
|
127
127
|
new.object_from_hash(nsc, hash)
|
@@ -60,11 +60,9 @@ module Nexpose
|
|
60
60
|
results << ve
|
61
61
|
end
|
62
62
|
results.keep_if { |v| v.status == status } unless status.nil?
|
63
|
-
|
63
|
+
results
|
64
64
|
end
|
65
|
-
|
66
|
-
alias_method :vuln_exceptions, :list_vuln_exceptions
|
67
|
-
|
65
|
+
alias vuln_exceptions list_vuln_exceptions
|
68
66
|
|
69
67
|
# Resubmit a vulnerability exception request with a new comment and reason
|
70
68
|
# after an exception has been rejected.
|
@@ -80,10 +78,10 @@ module Nexpose
|
|
80
78
|
# @return [Boolean] Whether or not the resubmission was valid.
|
81
79
|
#
|
82
80
|
def resubmit_vuln_exception(id, comment, reason = nil)
|
83
|
-
options
|
81
|
+
options = { 'exception-id' => id }
|
84
82
|
options['reason'] = reason if reason
|
85
|
-
xml
|
86
|
-
comment_xml
|
83
|
+
xml = make_xml('VulnerabilityExceptionResubmitRequest', options)
|
84
|
+
comment_xml = make_xml('comment', {}, comment, false)
|
87
85
|
xml.add_element(comment_xml)
|
88
86
|
r = execute(xml, '1.2')
|
89
87
|
r.success
|
@@ -115,22 +113,21 @@ module Nexpose
|
|
115
113
|
execute(xml, '1.2').success
|
116
114
|
end
|
117
115
|
|
118
|
-
|
119
116
|
private
|
120
117
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
118
|
+
def is_valid_vuln_exception_status?(status)
|
119
|
+
return true if status.nil?
|
120
|
+
valid_status = []
|
121
|
+
Nexpose::VulnException::Status.constants.each { |con| valid_status << Nexpose::VulnException::Status.const_get(con) }
|
122
|
+
valid_status << Nexpose::VulnException::Status.constants.map(&:to_s).map(&:downcase)
|
123
|
+
valid_status.flatten.map(&:downcase).include?(status.downcase)
|
124
|
+
end
|
128
125
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
end
|
126
|
+
def status_string_to_constant(status)
|
127
|
+
Nexpose::VulnException::Status.constants.find do |name|
|
128
|
+
Nexpose::VulnException::Status.const_get(name).to_s.downcase == status.downcase || status.to_sym.downcase == name.downcase
|
133
129
|
end
|
130
|
+
end
|
134
131
|
|
135
132
|
end
|
136
133
|
|
@@ -138,13 +135,13 @@ module Nexpose
|
|
138
135
|
#
|
139
136
|
# Certain attributes are necessary for some exception scopes, even though
|
140
137
|
# they are optional otherwise.
|
141
|
-
#
|
138
|
+
# - An exception for all instances of a vulnerability on all assets only
|
142
139
|
# requires the vuln_id attribute. The asset_id, vuln_key and port
|
143
140
|
# attributes are ignored for this scope type.
|
144
|
-
#
|
141
|
+
# - An exception for all instances on a specific asset requires the vuln_id
|
145
142
|
# and asset_id attributes. The vuln_key and port attributes are ignored for
|
146
143
|
# this scope type.
|
147
|
-
#
|
144
|
+
# - An exception for a specific instance of a vulnerability on a specific
|
148
145
|
# asset requires the vuln_id, asset_id. Additionally, the port and/or the
|
149
146
|
# key attribute must be specified.
|
150
147
|
#
|
@@ -169,8 +166,8 @@ module Nexpose
|
|
169
166
|
attr_accessor :scope
|
170
167
|
# ID of asset, if this exception applies to only one asset.
|
171
168
|
attr_accessor :asset_id
|
172
|
-
alias
|
173
|
-
alias
|
169
|
+
alias device_id asset_id
|
170
|
+
alias device_id= asset_id=
|
174
171
|
# Id of the site, if this exception applies to all instances on a site
|
175
172
|
attr_accessor :site_id
|
176
173
|
# ID of the Asset Group, if this exception applies to all instances on an asset group
|
@@ -193,9 +190,11 @@ module Nexpose
|
|
193
190
|
# Date when Submit occurred [Time]
|
194
191
|
attr_accessor :submit_date
|
195
192
|
|
196
|
-
|
197
193
|
def initialize(vuln_id, scope, reason, status = nil)
|
198
|
-
@vuln_id
|
194
|
+
@vuln_id = vuln_id
|
195
|
+
@scope = scope
|
196
|
+
@reason = reason
|
197
|
+
@status = status
|
199
198
|
end
|
200
199
|
|
201
200
|
# Submit this exception on the security console.
|
@@ -413,27 +412,27 @@ module Nexpose
|
|
413
412
|
#
|
414
413
|
module Status
|
415
414
|
UNDER_REVIEW = 'Under Review'
|
416
|
-
APPROVED
|
417
|
-
REJECTED
|
418
|
-
DELETED
|
415
|
+
APPROVED = 'Approved'
|
416
|
+
REJECTED = 'Rejected'
|
417
|
+
DELETED = 'Deleted'
|
419
418
|
end
|
420
419
|
|
421
420
|
# The reason for the exception status.
|
422
421
|
#
|
423
422
|
module Reason
|
424
|
-
FALSE_POSITIVE
|
423
|
+
FALSE_POSITIVE = 'False Positive'
|
425
424
|
COMPENSATING_CONTROL = 'Compensating Control'
|
426
|
-
ACCEPTABLE_USE
|
427
|
-
ACCEPTABLE_RISK
|
428
|
-
OTHER
|
425
|
+
ACCEPTABLE_USE = 'Acceptable Use'
|
426
|
+
ACCEPTABLE_RISK = 'Acceptable Risk'
|
427
|
+
OTHER = 'Other'
|
429
428
|
end
|
430
429
|
|
431
430
|
# The scope of the exception.
|
432
431
|
#
|
433
432
|
module Scope
|
434
|
-
ALL_INSTANCES
|
435
|
-
ALL_INSTANCES_ON_A_SPECIFIC_ASSET
|
436
|
-
ALL_INSTANCES_IN_A_SPECIFIC_SITE
|
433
|
+
ALL_INSTANCES = 'All Instances'
|
434
|
+
ALL_INSTANCES_ON_A_SPECIFIC_ASSET = 'All Instances on a Specific Asset'
|
435
|
+
ALL_INSTANCES_IN_A_SPECIFIC_SITE = 'All Instances in a Specific Site'
|
437
436
|
SPECIFIC_INSTANCE_OF_SPECIFIC_ASSET = 'Specific Instance of Specific Asset'
|
438
437
|
end
|
439
438
|
end
|
data/lib/nexpose/wait.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
module Nexpose
|
2
|
+
|
2
3
|
class Wait
|
3
4
|
attr_reader :error_message, :ready, :retry_count, :timeout, :polling_interval
|
4
5
|
|
5
6
|
def initialize(retry_count: nil, timeout: nil, polling_interval: nil)
|
6
|
-
@error_message
|
7
|
-
@ready
|
8
|
-
@retry_count
|
9
|
-
@timeout
|
7
|
+
@error_message = 'Default General Failure in Nexpose::Wait'
|
8
|
+
@ready = false
|
9
|
+
@retry_count = retry_count.to_i
|
10
|
+
@timeout = timeout
|
10
11
|
@polling_interval = polling_interval
|
11
12
|
end
|
12
13
|
|
@@ -18,49 +19,49 @@ module Nexpose
|
|
18
19
|
poller = Nexpose::Poller.new(timeout: @timeout, polling_interval: @polling_interval)
|
19
20
|
poller.wait(report_status_proc(nexpose_connection: nexpose_connection, report_id: report_id))
|
20
21
|
@ready = true
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
22
|
+
rescue Timeout::Error
|
23
|
+
@ready = false
|
24
|
+
retry if timeout_retry?
|
25
|
+
@error_message = "Timeout Waiting for Report to Generate - Report Config ID: #{report_id}"
|
26
|
+
rescue NoMethodError => error
|
27
|
+
@ready = false
|
28
|
+
@error_message = "Error Report Config ID: #{report_id} :: Report Probably Does Not Exist :: #{error}"
|
29
|
+
rescue => error
|
30
|
+
@ready = false
|
31
|
+
@error_message = "Error Report Config ID: #{report_id} :: #{error}"
|
31
32
|
end
|
32
33
|
|
33
34
|
def for_integration(nexpose_connection:, scan_id:, status: 'finished')
|
34
35
|
poller = Nexpose::Poller.new(timeout: @timeout, polling_interval: @polling_interval)
|
35
36
|
poller.wait(integration_status_proc(nexpose_connection: nexpose_connection, scan_id: scan_id, status: status))
|
36
37
|
@ready = true
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
rescue Timeout::Error
|
39
|
+
@ready = false
|
40
|
+
retry if timeout_retry?
|
41
|
+
@error_message = "Timeout Waiting for Integration Status of '#{status}' - Scan ID: #{scan_id}"
|
42
|
+
rescue Nexpose::APIError => error
|
43
|
+
@ready = false
|
44
|
+
@error_message = "API Error Waiting for Integration Scan ID: #{scan_id} :: #{error.req.error}"
|
44
45
|
end
|
45
46
|
|
46
47
|
def for_judgment(proc:, desc:)
|
47
48
|
poller = Nexpose::Poller.new(timeout: @timeout, polling_interval: @polling_interval)
|
48
49
|
poller.wait(proc)
|
49
50
|
@ready = true
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
rescue Timeout::Error
|
52
|
+
@ready = false
|
53
|
+
retry if timeout_retry?
|
54
|
+
@error_message = "Timeout Waiting for Judgment to Judge. #{desc}"
|
54
55
|
end
|
55
56
|
|
56
57
|
private
|
57
58
|
|
58
59
|
def report_status_proc(nexpose_connection:, report_id:)
|
59
|
-
|
60
|
+
proc { nexpose_connection.last_report(report_id).status == 'Generated' }
|
60
61
|
end
|
61
62
|
|
62
63
|
def integration_status_proc(nexpose_connection:, scan_id:, status:)
|
63
|
-
|
64
|
+
proc { nexpose_connection.scan_status(scan_id).downcase == status.downcase }
|
64
65
|
end
|
65
66
|
|
66
67
|
def timeout_retry?
|
@@ -71,6 +72,7 @@ module Nexpose
|
|
71
72
|
false
|
72
73
|
end
|
73
74
|
end
|
75
|
+
|
74
76
|
end
|
75
77
|
|
76
78
|
class Poller
|
@@ -89,7 +91,7 @@ module Nexpose
|
|
89
91
|
@poll_begin = Time.now
|
90
92
|
loop do
|
91
93
|
break if condition.call
|
92
|
-
raise
|
94
|
+
raise Timeout::Error if @poll_begin + @timeout < Time.now
|
93
95
|
sleep @polling_interval
|
94
96
|
end
|
95
97
|
end
|
@@ -105,5 +107,7 @@ module Nexpose
|
|
105
107
|
default_polling = 1
|
106
108
|
ENV['GLOBAL_POLLING_INTERVAL'].nil? ? default_polling : ENV['GLOBAL_POLLING_INTERVAL']
|
107
109
|
end
|
110
|
+
|
108
111
|
end
|
112
|
+
|
109
113
|
end
|
@@ -4,14 +4,13 @@ module Nexpose
|
|
4
4
|
module WebCredentials
|
5
5
|
|
6
6
|
module WebAppAuthType
|
7
|
-
HTML_FORM
|
7
|
+
HTML_FORM = 'htmlform' # Represent HTML form credentials.
|
8
8
|
HTTP_HEADER = 'httpheaders' # Represent HTTP header credentials.
|
9
9
|
end
|
10
10
|
|
11
11
|
# Object that represents Header name-value pairs, associated with Web Session Authentication.
|
12
12
|
#
|
13
13
|
class Header
|
14
|
-
|
15
14
|
# Name, one per Header
|
16
15
|
attr_reader :name
|
17
16
|
# Value, one per Header
|
@@ -19,7 +18,7 @@ module Nexpose
|
|
19
18
|
|
20
19
|
# Construct with name value pair
|
21
20
|
def initialize(name, value)
|
22
|
-
@name
|
21
|
+
@name = name
|
23
22
|
@value = value
|
24
23
|
end
|
25
24
|
|
@@ -28,16 +27,16 @@ module Nexpose
|
|
28
27
|
end
|
29
28
|
|
30
29
|
def to_h
|
31
|
-
header
|
30
|
+
header = {}
|
32
31
|
header[@name] = @value
|
33
32
|
header
|
34
33
|
end
|
34
|
+
|
35
35
|
end
|
36
36
|
|
37
37
|
# Object that represents Headers, associated with Web Session Authentication.
|
38
38
|
#
|
39
39
|
class Headers < APIObject
|
40
|
-
|
41
40
|
# A regular expression used to match against the response to identify authentication failures.
|
42
41
|
attr_reader :soft403Pattern
|
43
42
|
# Base URL of the application for which the form authentication applies.
|
@@ -48,20 +47,19 @@ module Nexpose
|
|
48
47
|
attr_reader :name
|
49
48
|
# is this enable for the site configuration
|
50
49
|
attr_accessor :enabled
|
51
|
-
#service type of header
|
50
|
+
# service type of header
|
52
51
|
attr_reader :service
|
53
52
|
# id of the header
|
54
53
|
attr_reader :id
|
55
54
|
|
56
|
-
|
57
55
|
def initialize(name, baseURL, soft403Pattern, id = -1, enabled = true)
|
58
|
-
@headers
|
59
|
-
@name
|
60
|
-
@baseURL
|
56
|
+
@headers = {}
|
57
|
+
@name = name
|
58
|
+
@baseURL = baseURL
|
61
59
|
@soft403Pattern = soft403Pattern
|
62
|
-
@service
|
63
|
-
@enabled
|
64
|
-
@id
|
60
|
+
@service = WebAppAuthType::HTTP_HEADER
|
61
|
+
@enabled = enabled
|
62
|
+
@id = id
|
65
63
|
end
|
66
64
|
|
67
65
|
def add_header(header)
|
@@ -79,8 +77,7 @@ module Nexpose
|
|
79
77
|
name: name,
|
80
78
|
headers: headers,
|
81
79
|
baseURL: baseURL,
|
82
|
-
soft403Pattern: soft403Pattern
|
83
|
-
}
|
80
|
+
soft403Pattern: soft403Pattern }
|
84
81
|
end
|
85
82
|
|
86
83
|
def ==(other)
|
@@ -96,7 +93,8 @@ module Nexpose
|
|
96
93
|
baseURL.eql?(other.baseURL) &&
|
97
94
|
soft403Pattern.eql?(other.soft403Pattern)
|
98
95
|
end
|
99
|
-
|
96
|
+
|
97
|
+
end
|
100
98
|
|
101
99
|
# When using HTML form, this represents the login form information.
|
102
100
|
#
|
@@ -116,9 +114,9 @@ module Nexpose
|
|
116
114
|
attr_reader :checked
|
117
115
|
|
118
116
|
def initialize(name, value, type, dynamic, checked)
|
119
|
-
@name
|
120
|
-
@value
|
121
|
-
@type
|
117
|
+
@name = name
|
118
|
+
@value = value
|
119
|
+
@type = type
|
122
120
|
@dynamic = dynamic
|
123
121
|
@checked = checked
|
124
122
|
end
|
@@ -136,12 +134,12 @@ module Nexpose
|
|
136
134
|
checked: checked
|
137
135
|
}
|
138
136
|
end
|
137
|
+
|
139
138
|
end
|
140
139
|
|
141
140
|
# When using HTML form, this represents the login form information.
|
142
141
|
#
|
143
142
|
class HTMLForm
|
144
|
-
|
145
143
|
# The name of the form being submitted.
|
146
144
|
attr_reader :name
|
147
145
|
# The HTTP action (URL) through which to submit the login form.
|
@@ -154,11 +152,11 @@ module Nexpose
|
|
154
152
|
attr_reader :fields
|
155
153
|
|
156
154
|
def initialize(name, action, method, encType)
|
157
|
-
@name
|
158
|
-
@action
|
159
|
-
@method
|
155
|
+
@name = name
|
156
|
+
@action = action
|
157
|
+
@method = method
|
160
158
|
@encType = encType
|
161
|
-
@fields
|
159
|
+
@fields = []
|
162
160
|
end
|
163
161
|
|
164
162
|
def add_field(field)
|
@@ -175,9 +173,9 @@ module Nexpose
|
|
175
173
|
method: method,
|
176
174
|
encType: encType,
|
177
175
|
fields: fields,
|
178
|
-
parentPage: action
|
179
|
-
}
|
176
|
+
parentPage: action }
|
180
177
|
end
|
178
|
+
|
181
179
|
end
|
182
180
|
|
183
181
|
# When using HTML form, this represents the login form information.
|
@@ -194,7 +192,7 @@ module Nexpose
|
|
194
192
|
attr_reader :name
|
195
193
|
# is this enable for the site configuration
|
196
194
|
attr_accessor :enabled
|
197
|
-
#service type of header
|
195
|
+
# service type of header
|
198
196
|
attr_reader :service
|
199
197
|
# id of the header
|
200
198
|
attr_reader :id
|
@@ -202,13 +200,13 @@ module Nexpose
|
|
202
200
|
attr_reader :form
|
203
201
|
|
204
202
|
def initialize(name, baseURL, loginURL, soft403Pattern, id = -1, enabled = true)
|
205
|
-
@name
|
206
|
-
@baseURL
|
207
|
-
@loginURL
|
203
|
+
@name = name
|
204
|
+
@baseURL = baseURL
|
205
|
+
@loginURL = loginURL
|
208
206
|
@soft403Pattern = soft403Pattern
|
209
|
-
@service
|
210
|
-
@enabled
|
211
|
-
@id
|
207
|
+
@service = WebAppAuthType::HTML_FORM
|
208
|
+
@enabled = enabled
|
209
|
+
@id = id
|
212
210
|
end
|
213
211
|
|
214
212
|
def add_html_form(html_form)
|
@@ -227,8 +225,7 @@ module Nexpose
|
|
227
225
|
form: form.to_h,
|
228
226
|
baseURL: baseURL,
|
229
227
|
loginURL: loginURL,
|
230
|
-
soft403Pattern: soft403Pattern
|
231
|
-
}
|
228
|
+
soft403Pattern: soft403Pattern }
|
232
229
|
end
|
233
230
|
|
234
231
|
def ==(other)
|
@@ -247,6 +244,7 @@ module Nexpose
|
|
247
244
|
end
|
248
245
|
|
249
246
|
end
|
247
|
+
|
250
248
|
end
|
251
|
-
end
|
252
249
|
|
250
|
+
end
|