nexpose 0.0.98 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +17 -7
- data/Rakefile +17 -22
- data/lib/README.md +5 -0
- data/lib/nexpose.rb +104 -130
- data/lib/nexpose/api_request.rb +133 -144
- data/lib/nexpose/common.rb +138 -0
- data/lib/nexpose/connection.rb +117 -106
- data/lib/nexpose/creds.rb +292 -279
- data/lib/nexpose/error.rb +21 -21
- data/lib/nexpose/manage.rb +83 -0
- data/lib/nexpose/misc.rb +85 -122
- data/lib/nexpose/report.rb +783 -603
- data/lib/nexpose/role.rb +27 -0
- data/lib/nexpose/scan.rb +264 -285
- data/lib/nexpose/scan_engine.rb +344 -350
- data/lib/nexpose/silo.rb +348 -347
- data/lib/nexpose/site.rb +826 -898
- data/lib/nexpose/ticket.rb +108 -108
- data/lib/nexpose/user.rb +223 -221
- data/lib/nexpose/util.rb +36 -36
- data/lib/nexpose/vuln.rb +510 -520
- metadata +37 -23
- data/README +0 -0
- data/nexpose.gemspec +0 -20
data/README.markdown
CHANGED
@@ -1,7 +1,17 @@
|
|
1
|
-
# Nexpose
|
2
|
-
|
3
|
-
This is the official gem package for the Ruby Nexpose API
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
# Nexpose
|
2
|
+
|
3
|
+
This is the official gem package for the Ruby Nexpose API.
|
4
|
+
|
5
|
+
For assistance with using the gem, to share your scripts, or to discuss different approaches, please visit the Rapid7 forums for Nexpose: https://community.rapid7.com/community/nexpose
|
6
|
+
|
7
|
+
## Contributions
|
8
|
+
|
9
|
+
This package is currently a work in progress. Most of the Nexpose API is exposed, but there are some operations missing. Also, there are stylistic differences between different calls that we hope to eliminate over time. We welcome contributions to this package. We ask only that pull requests and patches adhere to our coding standards.
|
10
|
+
|
11
|
+
* Favor returning classes over key-value maps. Classes tend to be easier for users to manipulate and use.
|
12
|
+
* Unless otherwise noted, code should adhere to the Ruby Style Guide: https://github.com/bbatsov/ruby-style-guide
|
13
|
+
* Use YARDoc comment style to improve the API documentation of the gem.
|
14
|
+
|
15
|
+
## Credits
|
16
|
+
|
17
|
+
Rapid7 LLC
|
data/Rakefile
CHANGED
@@ -1,22 +1,17 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
task :build
|
4
|
-
Rake::Task['clean'].execute
|
5
|
-
puts "[*] Building nexpose.gemspec"
|
6
|
-
system "gem build nexpose.gemspec &> /dev/null"
|
7
|
-
end
|
8
|
-
|
9
|
-
task :release => :build do
|
10
|
-
puts "[*] Pushing nexpose to rubygems.org"
|
11
|
-
system "gem push nexpose-*.gem &> /dev/null"
|
12
|
-
Rake::Task['clean'].execute
|
13
|
-
end
|
14
|
-
|
15
|
-
task :clean do
|
16
|
-
system "rm *.gem &> /dev/null"
|
17
|
-
end
|
18
|
-
|
19
|
-
task :update do
|
20
|
-
system "rm -f lib/nexpose.rb"
|
21
|
-
system "svn export https://metasploit.com/svn/framework3/trunk/lib/rapid7/nexpose.rb lib/nexpose.rb"
|
22
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
task :build do
|
4
|
+
Rake::Task['clean'].execute
|
5
|
+
puts "[*] Building nexpose.gemspec"
|
6
|
+
system "gem build nexpose.gemspec &> /dev/null"
|
7
|
+
end
|
8
|
+
|
9
|
+
task :release => :build do
|
10
|
+
puts "[*] Pushing nexpose to rubygems.org"
|
11
|
+
system "gem push nexpose-*.gem &> /dev/null"
|
12
|
+
Rake::Task['clean'].execute
|
13
|
+
end
|
14
|
+
|
15
|
+
task :clean do
|
16
|
+
system "rm *.gem &> /dev/null"
|
17
|
+
end
|
data/lib/README.md
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
# Nexpose Client
|
2
|
+
|
3
|
+
The nexpose.rb file should act simply as a means of collecing all the sub-elements of the client into a single module.
|
4
|
+
|
5
|
+
If adding or adjusting code, please note that all calls directly against the Connection object are currently implemented within the NexposeAPI module. This style of call should mostly be for listing and simple query calls, and not for configuration requests that will return an editable class.
|
data/lib/nexpose.rb
CHANGED
@@ -1,130 +1,104 @@
|
|
1
|
-
#
|
2
|
-
# The
|
3
|
-
#
|
4
|
-
=begin
|
5
|
-
|
6
|
-
Copyright (C) 2009-
|
7
|
-
All rights reserved.
|
8
|
-
|
9
|
-
Redistribution and use in source and binary forms, with or without modification,
|
10
|
-
are permitted provided that the following conditions are met:
|
11
|
-
|
12
|
-
* Redistributions of source code must retain the above copyright notice,
|
13
|
-
|
14
|
-
|
15
|
-
* Redistributions in binary form must reproduce the above copyright notice,
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
* Neither the name of Rapid7 LLC nor the names of its contributors
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
24
|
-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
25
|
-
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
27
|
-
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
28
|
-
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
29
|
-
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
30
|
-
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
31
|
-
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
32
|
-
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
-
|
34
|
-
=end
|
35
|
-
|
36
|
-
#
|
37
|
-
# WARNING! This code makes an SSL connection to the
|
38
|
-
# verify the certificate at this time. This can be a security issue if
|
39
|
-
# an attacker is able to man-in-the-middle the connection between the
|
40
|
-
# Metasploit console and the
|
41
|
-
# running
|
42
|
-
#
|
43
|
-
|
44
|
-
#
|
45
|
-
# WARNING! This code is still rough and going through substantive changes. While
|
46
|
-
# you can build tools using this library today, keep in mind that
|
47
|
-
# names and parameters may change in the future.
|
48
|
-
#
|
49
|
-
|
50
|
-
require 'date'
|
51
|
-
require 'rexml/document'
|
52
|
-
require 'net/https'
|
53
|
-
require 'net/http'
|
54
|
-
require 'uri'
|
55
|
-
require 'rex/mime'
|
56
|
-
require '
|
57
|
-
require 'nexpose/
|
58
|
-
require 'nexpose/
|
59
|
-
require 'nexpose/
|
60
|
-
require 'nexpose/
|
61
|
-
require 'nexpose/
|
62
|
-
require 'nexpose/
|
63
|
-
require 'nexpose/
|
64
|
-
require 'nexpose/
|
65
|
-
require 'nexpose/
|
66
|
-
require 'nexpose/
|
67
|
-
require 'nexpose/
|
68
|
-
require 'nexpose/
|
69
|
-
require 'nexpose/
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
#@date_mod = date('Ymd\THis000', @int_date)
|
106
|
-
date_mod = ''
|
107
|
-
return date_mod
|
108
|
-
end
|
109
|
-
|
110
|
-
# ==== Description
|
111
|
-
# Echos the last XML API request and response for the specified object. (Useful for debugging)
|
112
|
-
def self.printXML(object)
|
113
|
-
puts "request" + object.request_xml.to_s
|
114
|
-
puts "response is " + object.response_xml.to_s
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
def self.testa(ip, port, user, passwd)
|
119
|
-
nsc = Connection.new(ip, user, passwd, port)
|
120
|
-
|
121
|
-
nsc.login
|
122
|
-
site_listing = SiteListing.new(nsc)
|
123
|
-
|
124
|
-
site_listing.sites.each do |site|
|
125
|
-
puts "name is #{site.site_name}"
|
126
|
-
puts "id is #{site.id}"
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
end
|
1
|
+
#
|
2
|
+
# The Nexpose API
|
3
|
+
#
|
4
|
+
=begin
|
5
|
+
|
6
|
+
Copyright (C) 2009-2012, Rapid7 LLC
|
7
|
+
All rights reserved.
|
8
|
+
|
9
|
+
Redistribution and use in source and binary forms, with or without modification,
|
10
|
+
are permitted provided that the following conditions are met:
|
11
|
+
|
12
|
+
* Redistributions of source code must retain the above copyright notice,
|
13
|
+
this list of conditions and the following disclaimer.
|
14
|
+
|
15
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
this list of conditions and the following disclaimer in the documentation
|
17
|
+
and/or other materials provided with the distribution.
|
18
|
+
|
19
|
+
* Neither the name of Rapid7 LLC nor the names of its contributors
|
20
|
+
may be used to endorse or promote products derived from this software
|
21
|
+
without specific prior written permission.
|
22
|
+
|
23
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
24
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
25
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
27
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
28
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
29
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
30
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
31
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
32
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
|
34
|
+
=end
|
35
|
+
|
36
|
+
#
|
37
|
+
# WARNING! This code makes an SSL connection to the Nexpose server, but does NOT
|
38
|
+
# verify the certificate at this time. This can be a security issue if
|
39
|
+
# an attacker is able to man-in-the-middle the connection between the
|
40
|
+
# Metasploit console and the Nexpose server. In the common case of
|
41
|
+
# running Nexpose and Metasploit on the same host, this is a low risk.
|
42
|
+
#
|
43
|
+
|
44
|
+
#
|
45
|
+
# WARNING! This code is still rough and going through substantive changes. While
|
46
|
+
# you can build tools using this library today, keep in mind that
|
47
|
+
# method names and parameters may change in the future.
|
48
|
+
#
|
49
|
+
|
50
|
+
require 'date'
|
51
|
+
require 'rexml/document'
|
52
|
+
require 'net/https'
|
53
|
+
require 'net/http'
|
54
|
+
require 'uri'
|
55
|
+
require 'rex/mime'
|
56
|
+
require 'ipaddr'
|
57
|
+
require 'nexpose/error'
|
58
|
+
require 'nexpose/util'
|
59
|
+
require 'nexpose/user'
|
60
|
+
require 'nexpose/api_request'
|
61
|
+
require 'nexpose/manage'
|
62
|
+
require 'nexpose/misc'
|
63
|
+
require 'nexpose/report'
|
64
|
+
require 'nexpose/scan'
|
65
|
+
require 'nexpose/scan_engine'
|
66
|
+
require 'nexpose/silo'
|
67
|
+
require 'nexpose/site'
|
68
|
+
require 'nexpose/ticket'
|
69
|
+
require 'nexpose/vuln'
|
70
|
+
require 'nexpose/creds'
|
71
|
+
require 'nexpose/connection'
|
72
|
+
require 'nexpose/role'
|
73
|
+
require 'nexpose/common'
|
74
|
+
|
75
|
+
module Nexpose
|
76
|
+
|
77
|
+
# TODO add
|
78
|
+
def self.site_device_scan(connection, site_id, device_array, host_array, debug = false)
|
79
|
+
|
80
|
+
request_xml = '<SiteDevicesScanRequest session-id="' + connection.session_id.to_s + '" site-id="' + site_id.to_s + '">'
|
81
|
+
request_xml += '<Devices>'
|
82
|
+
device_array.each do |d|
|
83
|
+
request_xml += '<device id="' + d.to_s + '"/>'
|
84
|
+
end
|
85
|
+
request_xml += '</Devices>'
|
86
|
+
request_xml += '<Hosts>'
|
87
|
+
# The host array can only by single IP addresses for now. TODO: Expand to full API Spec.
|
88
|
+
host_array.each do |h|
|
89
|
+
request_xml += '<range from="' + h.to_s + '"/>'
|
90
|
+
end
|
91
|
+
request_xml += '</Hosts>'
|
92
|
+
request_xml += '</SiteDevicesScanRequest>'
|
93
|
+
|
94
|
+
r = connection.execute(request_xml)
|
95
|
+
r.success ? {:engine_id => r.attributes['engine_id'], :scan_id => r.attributes['scan-id']} : nil
|
96
|
+
end
|
97
|
+
|
98
|
+
# ==== Description
|
99
|
+
# Echos the last XML API request and response for the specified object. (Useful for debugging)
|
100
|
+
def self.printXML(object)
|
101
|
+
puts "request" + object.request_xml.to_s
|
102
|
+
puts "response is " + object.response_xml.to_s
|
103
|
+
end
|
104
|
+
end
|
data/lib/nexpose/api_request.rb
CHANGED
@@ -1,144 +1,133 @@
|
|
1
|
-
module Nexpose
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
def self.execute(url, req, api_version='1.1')
|
135
|
-
obj = self.new(req, url, api_version)
|
136
|
-
obj.execute
|
137
|
-
if (not obj.success)
|
138
|
-
raise APIError.new(obj, "Action failed: #{obj.error}")
|
139
|
-
end
|
140
|
-
obj
|
141
|
-
end
|
142
|
-
|
143
|
-
end
|
144
|
-
end
|
1
|
+
module Nexpose
|
2
|
+
class APIRequest
|
3
|
+
include XMLUtils
|
4
|
+
|
5
|
+
attr_reader :http
|
6
|
+
attr_reader :uri
|
7
|
+
attr_reader :headers
|
8
|
+
attr_reader :retry_count
|
9
|
+
attr_reader :time_out
|
10
|
+
attr_reader :pause
|
11
|
+
|
12
|
+
attr_reader :req
|
13
|
+
attr_reader :res
|
14
|
+
attr_reader :sid
|
15
|
+
attr_reader :success
|
16
|
+
|
17
|
+
attr_reader :error
|
18
|
+
attr_reader :trace
|
19
|
+
|
20
|
+
attr_reader :raw_response
|
21
|
+
attr_reader :raw_response_data
|
22
|
+
|
23
|
+
def initialize(req, url, api_version='1.1')
|
24
|
+
@url = url
|
25
|
+
@req = req
|
26
|
+
@api_version = api_version
|
27
|
+
@url = @url.sub('API_VERSION', @api_version)
|
28
|
+
prepare_http_client
|
29
|
+
end
|
30
|
+
|
31
|
+
def prepare_http_client
|
32
|
+
@retry_count = 0
|
33
|
+
@retry_count_max = 10
|
34
|
+
@time_out = 30
|
35
|
+
@pause = 2
|
36
|
+
@uri = URI.parse(@url)
|
37
|
+
@http = Net::HTTP.new(@uri.host, @uri.port)
|
38
|
+
@http.use_ssl = true
|
39
|
+
#
|
40
|
+
# XXX: This is obviously a security issue, however, we handle this at the client level by forcing
|
41
|
+
# a confirmation when the nexpose host is not localhost. In a perfect world, we would present
|
42
|
+
# the server signature before accepting it, but this requires either a direct callback inside
|
43
|
+
# of this module back to whatever UI, or opens a race condition between accept and attempt.
|
44
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
45
|
+
@headers = {'Content-Type' => 'text/xml'}
|
46
|
+
@success = false
|
47
|
+
end
|
48
|
+
|
49
|
+
def execute
|
50
|
+
@conn_tries = 0
|
51
|
+
|
52
|
+
begin
|
53
|
+
prepare_http_client
|
54
|
+
@raw_response = @http.post(@uri.path, @req, @headers)
|
55
|
+
@raw_response_data = @raw_response.read_body
|
56
|
+
@res = parse_xml(@raw_response_data)
|
57
|
+
|
58
|
+
if (not @res.root)
|
59
|
+
@error = 'Nexpose service returned invalid XML.'
|
60
|
+
return @sid
|
61
|
+
end
|
62
|
+
|
63
|
+
@sid = attributes['session-id']
|
64
|
+
|
65
|
+
if (attributes['success'] and attributes['success'].to_i == 1)
|
66
|
+
@success = true
|
67
|
+
elsif @api_version =~ /1.2/ and @res and (@res.get_elements '//Exception').count < 1
|
68
|
+
@success = true
|
69
|
+
else
|
70
|
+
@success = false
|
71
|
+
@res.elements.each('//Failure/Exception') do |s|
|
72
|
+
s.elements.each('message') do |m|
|
73
|
+
@error = m.text
|
74
|
+
end
|
75
|
+
s.elements.each('stacktrace') do |m|
|
76
|
+
@trace = m.text
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
# This is a hack to handle corner cases where a heavily loaded Nexpose instance
|
81
|
+
# drops our HTTP connection before processing. We try 5 times to establish a
|
82
|
+
# connection in these situations. The actual exception occurs in the Ruby
|
83
|
+
# http library, which is why we use such generic error classes.
|
84
|
+
rescue OpenSSL::SSL::SSLError
|
85
|
+
if @conn_tries < 5
|
86
|
+
@conn_tries += 1
|
87
|
+
retry
|
88
|
+
end
|
89
|
+
rescue ::ArgumentError, ::NoMethodError
|
90
|
+
if @conn_tries < 5
|
91
|
+
@conn_tries += 1
|
92
|
+
retry
|
93
|
+
end
|
94
|
+
rescue ::Timeout::Error
|
95
|
+
if @conn_tries < 5
|
96
|
+
@conn_tries += 1
|
97
|
+
retry
|
98
|
+
end
|
99
|
+
@error = 'Nexpose host did not respond.'
|
100
|
+
rescue ::Errno::EHOSTUNREACH, ::Errno::ENETDOWN, ::Errno::ENETUNREACH, ::Errno::ENETRESET, ::Errno::EHOSTDOWN, ::Errno::EACCES, ::Errno::EINVAL, ::Errno::EADDRNOTAVAIL
|
101
|
+
@error = 'Nexpose host is unreachable.'
|
102
|
+
# Handle console-level interrupts
|
103
|
+
rescue ::Interrupt
|
104
|
+
@error = 'Received a user interrupt.'
|
105
|
+
rescue ::Errno::ECONNRESET, ::Errno::ECONNREFUSED, ::Errno::ENOTCONN, ::Errno::ECONNABORTED
|
106
|
+
@error = 'Nexpose service is not available.'
|
107
|
+
rescue ::REXML::ParseException
|
108
|
+
@error = 'Nexpose has not been properly licensed.'
|
109
|
+
end
|
110
|
+
|
111
|
+
if !(@success or @error)
|
112
|
+
@error = "Nexpose service returned an unrecognized response: #{@raw_response_data.inspect}"
|
113
|
+
end
|
114
|
+
|
115
|
+
@sid
|
116
|
+
end
|
117
|
+
|
118
|
+
def attributes(*args)
|
119
|
+
return if not @res.root
|
120
|
+
@res.root.attributes(*args)
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.execute(url, req, api_version='1.1')
|
124
|
+
obj = self.new(req, url, api_version)
|
125
|
+
obj.execute
|
126
|
+
if (not obj.success)
|
127
|
+
raise APIError.new(obj, "Action failed: #{obj.error}")
|
128
|
+
end
|
129
|
+
obj
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|