nexpose 6.1.1 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING CHANGED
@@ -1,33 +1,29 @@
1
- Copyright (C) 2014, Rapid7, Inc.
2
- All rights reserved.
3
-
4
- Redistribution and use in source and binary forms, with or without modification,
5
- are permitted provided that the following conditions are met:
6
-
7
- * Redistributions of source code must retain the above copyright notice,
8
- this list of conditions and the following disclaimer.
9
-
10
- * Redistributions in binary form must reproduce the above copyright notice,
11
- this list of conditions and the following disclaimer in the documentation
12
- and/or other materials provided with the distribution.
1
+ BSD 3-Clause License
13
2
 
14
- * Neither the name of Rapid7, Inc. nor the names of its contributors
15
- may be used to endorse or promote products derived from this software
16
- without specific prior written permission.
17
-
18
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
-
29
- ================================================================================
30
-
31
- The nexpose-client gem is provided under the 3-clause BSD license above.
3
+ Copyright (c) 2014-2017, Rapid7, Inc.
4
+ All rights reserved.
32
5
 
33
- The copyright on this package is held by Rapid7, Inc.
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -1,53 +1,93 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nexpose (6.1.1)
4
+ nexpose (7.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- addressable (2.3.7)
10
- ast (2.0.0)
11
- astrolabe (1.3.0)
12
- parser (>= 2.2.0.pre.3, < 3.0)
13
- codeclimate-test-reporter (0.4.7)
9
+ activesupport (4.2.8)
10
+ i18n (~> 0.7)
11
+ minitest (~> 5.1)
12
+ thread_safe (~> 0.3, >= 0.3.4)
13
+ tzinfo (~> 1.1)
14
+ addressable (2.5.1)
15
+ public_suffix (~> 2.0, >= 2.0.2)
16
+ ast (2.3.0)
17
+ codeclimate-test-reporter (0.4.8)
14
18
  simplecov (>= 0.7.1, < 1.0.0)
15
- crack (0.4.2)
19
+ coderay (1.1.1)
20
+ crack (0.4.3)
16
21
  safe_yaml (~> 1.0.0)
17
- diff-lcs (1.2.5)
22
+ diff-lcs (1.3)
18
23
  docile (1.1.5)
19
- multi_json (1.10.1)
20
- parser (2.2.0.3)
21
- ast (>= 1.1, < 3.0)
22
- powerpack (0.1.0)
23
- rainbow (2.0.0)
24
- rake (10.4.2)
25
- rspec (3.2.0)
26
- rspec-core (~> 3.2.0)
27
- rspec-expectations (~> 3.2.0)
28
- rspec-mocks (~> 3.2.0)
29
- rspec-core (3.2.1)
30
- rspec-support (~> 3.2.0)
31
- rspec-expectations (3.2.0)
24
+ faraday (0.12.0.1)
25
+ multipart-post (>= 1.2, < 3)
26
+ faraday-http-cache (2.0.0)
27
+ faraday (~> 0.8)
28
+ github_changelog_generator (1.14.3)
29
+ activesupport
30
+ faraday-http-cache
31
+ multi_json
32
+ octokit (~> 4.6)
33
+ rainbow (>= 2.1)
34
+ rake (>= 10.0)
35
+ retriable (~> 2.1)
36
+ i18n (0.8.1)
37
+ method_source (0.8.2)
38
+ minitest (5.10.1)
39
+ multi_json (1.12.1)
40
+ multipart-post (2.0.0)
41
+ octokit (4.7.0)
42
+ sawyer (~> 0.8.0, >= 0.5.3)
43
+ parallel (1.12.0)
44
+ parser (2.4.0.0)
45
+ ast (~> 2.2)
46
+ powerpack (0.1.1)
47
+ pry (0.9.12.6)
48
+ coderay (~> 1.0)
49
+ method_source (~> 0.8)
50
+ slop (~> 3.4)
51
+ public_suffix (2.0.5)
52
+ rainbow (2.2.2)
53
+ rake
54
+ rake (12.0.0)
55
+ retriable (2.1.0)
56
+ rspec (3.6.0)
57
+ rspec-core (~> 3.6.0)
58
+ rspec-expectations (~> 3.6.0)
59
+ rspec-mocks (~> 3.6.0)
60
+ rspec-core (3.6.0)
61
+ rspec-support (~> 3.6.0)
62
+ rspec-expectations (3.6.0)
32
63
  diff-lcs (>= 1.2.0, < 2.0)
33
- rspec-support (~> 3.2.0)
34
- rspec-mocks (3.2.1)
64
+ rspec-support (~> 3.6.0)
65
+ rspec-mocks (3.6.0)
35
66
  diff-lcs (>= 1.2.0, < 2.0)
36
- rspec-support (~> 3.2.0)
37
- rspec-support (3.2.2)
38
- rubocop (0.29.1)
39
- astrolabe (~> 1.3)
40
- parser (>= 2.2.0.1, < 3.0)
67
+ rspec-support (~> 3.6.0)
68
+ rspec-support (3.6.0)
69
+ rubocop (0.49.1)
70
+ parallel (~> 1.10)
71
+ parser (>= 2.3.3.1, < 3.0)
41
72
  powerpack (~> 0.1)
42
73
  rainbow (>= 1.99.1, < 3.0)
43
- ruby-progressbar (~> 1.4)
44
- ruby-progressbar (1.7.1)
74
+ ruby-progressbar (~> 1.7)
75
+ unicode-display_width (~> 1.0, >= 1.0.1)
76
+ ruby-progressbar (1.8.1)
45
77
  safe_yaml (1.0.4)
78
+ sawyer (0.8.1)
79
+ addressable (>= 2.3.5, < 2.6)
80
+ faraday (~> 0.8, < 1.0)
46
81
  simplecov (0.9.2)
47
82
  docile (~> 1.1.0)
48
83
  multi_json (~> 1.0)
49
84
  simplecov-html (~> 0.9.0)
50
85
  simplecov-html (0.9.0)
86
+ slop (3.6.0)
87
+ thread_safe (0.3.6)
88
+ tzinfo (1.2.3)
89
+ thread_safe (~> 0.1)
90
+ unicode-display_width (1.3.0)
51
91
  vcr (2.9.3)
52
92
  webmock (1.20.4)
53
93
  addressable (>= 2.3.6)
@@ -59,7 +99,9 @@ PLATFORMS
59
99
  DEPENDENCIES
60
100
  bundler (~> 1.3)
61
101
  codeclimate-test-reporter (~> 0.4.6)
102
+ github_changelog_generator
62
103
  nexpose!
104
+ pry (= 0.9.12.6)
63
105
  rake
64
106
  rspec (~> 3.2)
65
107
  rubocop
@@ -3,7 +3,7 @@
3
3
 
4
4
  This is the official gem package for the Ruby Nexpose API client library.
5
5
 
6
- For assistance with using the gem, to share your scripts, or to discuss different approaches, please visit the Rapid7 community: https://community.rapid7.com/
6
+ For assistance with using the gem or to discuss different approaches, please open an issue. To share or discuss scripts which use the gem head over to the [Nexpose Resources](https://github.com/rapid7/nexpose-resources) project.
7
7
 
8
8
  Check out the [wiki](https://github.com/rapid7/nexpose-client/wiki) for walk-throughs and other documentation. Submit bugs and feature requests on the [issues](https://github.com/rapid7/nexpose-client/issues) page.
9
9
 
@@ -25,6 +25,8 @@ Our coding standards include:
25
25
  * Unless otherwise noted, code should adhere to the Ruby Style Guide: https://github.com/bbatsov/ruby-style-guide
26
26
  * Use YARDoc comment style to improve the API documentation of the gem.
27
27
 
28
+ Full usage examples or task-oriented scripts should be submitted to the [Nexpose Resources](https://github.com/rapid7/nexpose-resources) project. Smaller examples can be added to the [wiki](https://github.com/rapid7/nexpose-client/wiki).
29
+
28
30
  ## License
29
31
 
30
32
  The nexpose-client gem is provided under the 3-Clause BSD License. See [COPYING](COPYING) for details.
data/Rakefile CHANGED
@@ -4,3 +4,12 @@ require 'bundler/gem_tasks'
4
4
  task :clean do
5
5
  system "rm *.gem &> /dev/null"
6
6
  end
7
+
8
+
9
+ require 'github_changelog_generator/task'
10
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
11
+ token = ENV['CHANGELOG_GITHUB_TOKEN']
12
+ if token.nil?
13
+ warn "!!WARNING!! Missing Github Token Environment Variable. Fix before you run rake changelog. !!WARNING!!"
14
+ end
15
+ end
@@ -68,6 +68,7 @@ require 'nexpose/asset'
68
68
  require 'nexpose/blackout'
69
69
  require 'nexpose/common'
70
70
  require 'nexpose/console'
71
+ require 'nexpose/credential_helper'
71
72
  require 'nexpose/credential'
72
73
  require 'nexpose/site_credentials'
73
74
  require 'nexpose/shared_credential'
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+
2
3
  module Nexpose
3
4
  # Accessor to the Nexpose AJAX API.
4
5
  # These core methods should allow direct access to underlying controllers
@@ -133,7 +134,8 @@ module Nexpose
133
134
  # Use the Nexpose::Connection to establish a correct HTTPS object.
134
135
  def https(nsc, timeout = nil)
135
136
  http = Net::HTTP.new(nsc.host, nsc.port)
136
- http.read_timeout = timeout if timeout
137
+ http.read_timeout = (timeout || nsc.timeout)
138
+ http.open_timeout = nsc.open_timeout
137
139
  http.use_ssl = true
138
140
  if nsc.trust_store.nil?
139
141
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
@@ -183,8 +185,8 @@ module Nexpose
183
185
  def get_request_api_version(request)
184
186
  matches = request.path.match(API_PATTERN)
185
187
  matches[:version].to_f
186
- rescue
187
- 0.0
188
+ rescue
189
+ 0.0
188
190
  end
189
191
 
190
192
  # Get an error message from the response body if the request url api version
@@ -192,7 +194,7 @@ module Nexpose
192
194
  def get_error_message(request, response)
193
195
  version = get_request_api_version(request)
194
196
  data_request = use_response_error_message?(request, response)
195
- return_response = (version >= 2.1 || data_request )
197
+ return_response = (version >= 2.1 || data_request)
196
198
  (return_response && response.body) ? "response body: #{response.body}" : "request body: #{request.body}"
197
199
  end
198
200
 
@@ -202,7 +204,7 @@ module Nexpose
202
204
  if (request.path.include?('/data/') && !response.content_type.nil?)
203
205
  response.content_type.include? 'text/plain'
204
206
  else
205
- return false
207
+ false
206
208
  end
207
209
  end
208
210
 
@@ -253,7 +255,7 @@ module Nexpose
253
255
  pref_key = "#{pref}.rows"
254
256
  resp = get(nsc, uri)
255
257
  json = JSON.parse(resp)
256
- if json.has_key?(pref_key)
258
+ if json.key?(pref_key)
257
259
  rows = json[pref_key].to_i
258
260
  rows > 0 ? rows : 10
259
261
  else
@@ -42,17 +42,16 @@ module Nexpose
42
42
  else
43
43
  @http.cert_store = @trust_store
44
44
  end
45
- @headers = {'Content-Type' => 'text/xml'}
45
+ @headers = { 'Content-Type' => 'text/xml' }
46
46
  @success = false
47
47
  end
48
48
 
49
49
  def execute(options = {})
50
50
  @conn_tries = 0
51
-
52
51
  begin
53
52
  prepare_http_client
54
- @http.read_timeout = options[:timeout] if options.key? :timeout
55
- @http.open_timeout = options.key?(:open_timeout) ? options[:open_timeout] : 60
53
+ @http.read_timeout = options.key?(:timeout) ? options[:timeout] : 120
54
+ @http.open_timeout = options.key?(:open_timeout) ? options[:open_timeout] : 120
56
55
  @raw_response = @http.post(@uri.path, @req, @headers)
57
56
  @raw_response_data = @raw_response.read_body
58
57
 
@@ -62,7 +61,7 @@ module Nexpose
62
61
  @success = true
63
62
  else
64
63
  @success = false
65
- @error = "User requested raw XML response. Not parsing failures."
64
+ @error = 'User requested raw XML response. Not parsing failures.'
66
65
  end
67
66
  else
68
67
  @res = parse_xml(@raw_response_data)
@@ -74,19 +73,19 @@ module Nexpose
74
73
 
75
74
  @sid = attributes['session-id']
76
75
 
77
- if (attributes['success'] and attributes['success'].to_i == 1)
76
+ if (attributes['success'] && attributes['success'].to_i == 1)
78
77
  @success = true
79
- elsif @api_version =~ /1.2/ and @res and (@res.get_elements '//Exception').count < 1
78
+ elsif @api_version =~ /1.2/ && @res && (@res.get_elements '//Exception').count < 1
80
79
  @success = true
81
80
  else
82
81
  @success = false
83
82
  if @api_version =~ /1.2/
84
83
  @res.elements.each('//Exception/Message') do |message|
85
- @error = message.text.sub(/.*Exception: */, '')
84
+ @error = message.text.sub(/.*Exception: */, '')
85
+ end
86
+ @res.elements.each('//Exception/Stacktrace') do |stacktrace|
87
+ @trace = stacktrace.text
86
88
  end
87
- @res.elements.each('//Exception/Stacktrace') do |stacktrace|
88
- @trace = stacktrace.text
89
- end
90
89
  else
91
90
  @res.elements.each('//message') do |message|
92
91
  @error = message.text.sub(/.*Exception: */, '')
@@ -97,27 +96,29 @@ module Nexpose
97
96
  end
98
97
  end
99
98
  end
100
- # This is a hack to handle corner cases where a heavily loaded Nexpose instance
101
- # drops our HTTP connection before processing. We try 5 times to establish a
102
- # connection in these situations. The actual exception occurs in the Ruby
103
- # http library, which is why we use such generic error classes.
104
- rescue OpenSSL::SSL::SSLError => e
99
+ # This is a hack to handle corner cases where a heavily loaded Nexpose instance
100
+ # drops our HTTP connection before processing. We try 5 times to establish a
101
+ # connection in these situations. The actual exception occurs in the Ruby
102
+ # http library, which is why we use such generic error classes.
103
+ rescue OpenSSL::SSL::SSLError => error
105
104
  if @conn_tries < 5
106
105
  @conn_tries += 1
106
+ $stderr.puts "\n\nRetrying the request due to #{error}. If you see this message please open an Issue on Github with the error.\n\n"
107
107
  retry
108
108
  end
109
- rescue ::ArgumentError, ::NoMethodError => e
109
+ rescue ::ArgumentError, ::NoMethodError => error
110
110
  if @conn_tries < 5
111
111
  @conn_tries += 1
112
+ $stderr.puts "\n\nRetrying the request due to #{error}. If you see this message please open an Issue on Github with the error.\n\n"
112
113
  retry
113
114
  end
114
- rescue ::Timeout::Error
115
- if @conn_tries < 5
116
- @conn_tries += 1
117
- # If an explicit timeout is set, don't retry.
118
- retry unless options.key? :timeout
119
- end
120
- @error = "Nexpose did not respond within #{@http.read_timeout} seconds."
115
+ ### HTTP Specific Timeout Errors.
116
+ rescue ::Net::ReadTimeout, ::Net::OpenTimeout => error
117
+ timeout_value = error.instance_of?(Net::ReadTimeout) ? @http.read_timeout : @http.open_timeout
118
+ @error = "Nexpose did not respond within #{timeout_value} seconds #{error}. Reference the Wiki for information on setting the different Timeout values."
119
+ ### Catch all Timeout Error.
120
+ rescue ::Timeout::Error => error
121
+ @error = "Nexpose did not respond within #{@http.read_timeout} seconds #{error}. Reference the Wiki for information on setting the different Timeout values."
121
122
  rescue ::Errno::EHOSTUNREACH, ::Errno::ENETDOWN, ::Errno::ENETUNREACH, ::Errno::ENETRESET, ::Errno::EHOSTDOWN, ::Errno::EACCES, ::Errno::EINVAL, ::Errno::EADDRNOTAVAIL
122
123
  @error = 'Nexpose host is unreachable.'
123
124
  # Handle console-level interrupts
@@ -129,7 +130,7 @@ module Nexpose
129
130
  @error = "Error parsing response: #{exc.message}"
130
131
  end
131
132
 
132
- if !(@success or @error)
133
+ if !(@success || @error)
133
134
  @error = "Nexpose service returned an unrecognized response: #{@raw_response_data.inspect}"
134
135
  end
135
136
 
@@ -137,7 +138,7 @@ module Nexpose
137
138
  end
138
139
 
139
140
  def attributes(*args)
140
- return if not @res.root
141
+ return unless @res.root
141
142
  @res.root.attributes(*args)
142
143
  end
143
144
 
@@ -51,14 +51,20 @@ module Nexpose
51
51
  attr_reader :url
52
52
  # The token used to login to the NSC
53
53
  attr_reader :token
54
-
55
54
  # The last XML request sent by this object, useful for debugging.
56
55
  attr_reader :request_xml
57
56
  # The last XML response received by this object, useful for debugging.
58
57
  attr_reader :response_xml
59
-
60
58
  # The trust store to validate connections against if any
61
59
  attr_reader :trust_store
60
+ # The main HTTP read_timeout value
61
+ # For more information visit the link below:
62
+ # https://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html#read_timeout-attribute-method
63
+ attr_accessor :timeout
64
+ # The optional HTTP open_timeout value
65
+ # For more information visit the link below:
66
+ # http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html#open_timeout-attribute-method
67
+ attr_accessor :open_timeout
62
68
 
63
69
  # A constructor to load a Connection object from a URI
64
70
  def self.from_uri(uri, user, pass, silo_id = nil, token = nil, trust_cert = nil)
@@ -76,23 +82,23 @@ module Nexpose
76
82
  # @param [String] token The two-factor authentication (2FA) token for Nexpose sessions.
77
83
  # @param [String] trust_cert The PEM-formatted web certificate of the Nexpose console. Used for SSL validation.
78
84
  def initialize(ip, user, pass, port = 3780, silo_id = nil, token = nil, trust_cert = nil)
79
- @host = ip
80
- @port = port
81
- @username = user
82
- @password = pass
83
- @token = token
84
- @silo_id = silo_id
85
- unless trust_cert.nil?
86
- @trust_store = create_trust_store(trust_cert)
87
- end
88
- @session_id = nil
89
- @url = "https://#{@host}:#{@port}/api/API_VERSION/xml"
85
+ @host = ip
86
+ @username = user
87
+ @password = pass
88
+ @port = port
89
+ @silo_id = silo_id
90
+ @token = token
91
+ @trust_store = create_trust_store(trust_cert) unless trust_cert.nil?
92
+ @session_id = nil
93
+ @url = "https://#{@host}:#{@port}/api/API_VERSION/xml"
94
+ @timeout = 120
95
+ @open_timeout = 120
90
96
  end
91
97
 
92
98
  # Establish a new connection and Session ID
93
99
  def login
94
100
  begin
95
- login_hash = {'sync-id' => 0, 'password' => @password, 'user-id' => @username, 'token' => @token}
101
+ login_hash = { 'sync-id' => 0, 'password' => @password, 'user-id' => @username, 'token' => @token }
96
102
  login_hash['silo-id'] = @silo_id if @silo_id
97
103
  r = execute(make_xml('LoginRequest', login_hash))
98
104
  if r.success
@@ -106,13 +112,15 @@ module Nexpose
106
112
 
107
113
  # Logout of the current connection
108
114
  def logout
109
- r = execute(make_xml('LogoutRequest', {'sync-id' => 0}))
115
+ r = execute(make_xml('LogoutRequest', { 'sync-id' => 0 }))
110
116
  return true if r.success
111
117
  raise APIError.new(r, 'Logout failed')
112
118
  end
113
119
 
114
120
  # Execute an API request
115
121
  def execute(xml, version = '1.1', options = {})
122
+ options.store(:timeout, @timeout) unless options.key?(:timeout)
123
+ options.store(:open_timeout, @open_timeout)
116
124
  @request_xml = xml.to_s
117
125
  @api_version = version
118
126
  response = APIRequest.execute(@url, @request_xml, @api_version, options, @trust_store)
@@ -127,17 +135,17 @@ module Nexpose
127
135
  # Would need to do something more sophisticated to grab
128
136
  # all the associated image files.
129
137
  def download(url, file_name = nil)
130
- return nil if url.nil? or url.empty?
131
- uri = URI.parse(url)
132
- http = Net::HTTP.new(@host, @port)
138
+ return nil if (url.nil? || url.empty?)
139
+ uri = URI.parse(url)
140
+ http = Net::HTTP.new(@host, @port)
133
141
  http.use_ssl = true
134
142
  if @trust_store.nil?
135
143
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE # XXX: security issue
136
144
  else
137
145
  http.cert_store = @trust_store
138
146
  end
139
- headers = {'Cookie' => "nexposeCCSessionID=#{@session_id}"}
140
- resp = http.get(uri.to_s, headers)
147
+ headers = { 'Cookie' => "nexposeCCSessionID=#{@session_id}" }
148
+ resp = http.get(uri.to_s, headers)
141
149
 
142
150
  if file_name
143
151
  ::File.open(file_name, 'wb') { |file| file.write(resp.body) }