controls 1.2.0 → 1.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d97c792ec22e7db59c7f591f023942e40b9cf6c
4
- data.tar.gz: 59d3fafbcb9633a88a43935c72e90c5d66ea8878
3
+ metadata.gz: f428c9a710108971da0e6995f4f0ca0032caeed4
4
+ data.tar.gz: e727ddbd5d77bc6afdfd84ef51a81bc57bc8dfc4
5
5
  SHA512:
6
- metadata.gz: eee56d732f6779946baa87cc77afeb38587d5abe8ac004cad782da8c5f9d6ee39ce711d932da15cfe1ab51bbb13ac5daa24fecf8edac6e7e6bc1e17c660c594b
7
- data.tar.gz: 6e6a7ae9442977487ba0d449a0fc5ecd500360b038c920f4477b1f5e2f15d818eb766dbbe4ab68edc057c947a3cf13884c80d9e9648562bcff69a0fd3fbab1e4
6
+ metadata.gz: 1455b974d58516093e986277014a653b157ab5f1a0da5d22742b7554a5671074f001ae458ab14cff15cf18ffdc7a5b7c1742c713aea4eb0a41b21bae8466d111
7
+ data.tar.gz: fd418654c0932982591cd8d717354796194dd376a7214397fb553f348b1d742f5cedd64cddc18237bd6e2eb3dbf280a4c890a05fb36d2901f1c9d18595efb99d
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # controlsinsight client gem
2
- The **controls**insight (controls) gem interfaces with [Rapid7's **controls**insight API](http://rapid7.viewdocs.io/controlsinsight.rb).
2
+ The **controls**insight (controls) gem interfaces with [Rapid7's **controls**insight API](http://rapid7.github.io/controlsinsight.rb).
3
3
 
4
4
  ## Installation
5
5
  Add this line to your application's Gemfile:
@@ -15,7 +15,7 @@ Or install it yourself as:
15
15
  $ gem install controls
16
16
 
17
17
  ## Documentation
18
- * [viewdocs.io API documentation](http://rapid7.viewdocs.io/controlsinsight.rb)
18
+ * [API documentation](http://rapid7.github.io/controlsinsight.rb)
19
19
  * [YARD documentation for the Ruby client](http://www.rubydoc.info/github/rapid7/controlsinsight.rb)
20
20
 
21
21
  ## Basic Resources
@@ -101,4 +101,4 @@ Controls.configuration_trends('configuration-name-here')
101
101
  ```
102
102
 
103
103
  ## License
104
- This project was created by [Erran Carey (@ipwnstuff)](http://ipwnstuff.github.io) and licensed under [the MIT License](LICENSE.md).
104
+ This project was created by [Erran Carey (@erran)](http://erran.github.io) and licensed under [the MIT License](LICENSE.md).
data/controls.gemspec CHANGED
@@ -18,9 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = %w[lib]
20
20
 
21
- spec.add_dependency 'activesupport'
21
+ spec.add_dependency 'dish'
22
22
  spec.add_dependency 'faraday', '< 0.9'
23
- spec.add_dependency 'nokogiri'
23
+ spec.add_dependency 'rack'
24
24
 
25
25
  spec.add_development_dependency 'bundler', '~> 1.3'
26
26
  spec.add_development_dependency 'netrc'
data/lib/controls.rb CHANGED
@@ -3,6 +3,8 @@ require 'controls/default'
3
3
 
4
4
  # A Ruby client for the **controls**insight API
5
5
  module Controls
6
+ Error = Class.new(StandardError)
7
+
6
8
  class << self
7
9
  include Controls::Configurable
8
10
 
@@ -1,6 +1,7 @@
1
- require 'faraday'
2
1
  require 'json'
2
+ require 'faraday'
3
3
  require 'nokogiri'
4
+ require 'rack/utils'
4
5
  require 'controls/authentication'
5
6
  require 'controls/configurable'
6
7
  require 'controls/client/assessments'
@@ -88,8 +89,16 @@ module Controls
88
89
  headers = connection_options[:headers].merge(headers)
89
90
  url = URI.escape(File.join(api_endpoint, path))
90
91
  resp = middleware.get(url, params, headers)
92
+ @_last_request = {
93
+ response: resp,
94
+ path: path
95
+ }
96
+
97
+ if !resp.headers['content-type'].eql?("application/json;charset=UTF-8")
98
+ fail exception('Invalid content-type error')
99
+ end
91
100
 
92
- Response.parse(resp.body)
101
+ Response.parse(resp.body, path)
93
102
  rescue Faraday::Error::ConnectionFailed => e
94
103
  if e.message =~ /^SSL_connect/
95
104
  warn(*SSL_WARNING)
@@ -105,8 +114,16 @@ module Controls
105
114
  headers = connection_options[:headers].merge(headers)
106
115
  url = URI.escape(File.join(api_endpoint, path))
107
116
  resp = middleware.put(url, body, headers, &block)
117
+ @_last_request = {
118
+ response: resp,
119
+ path: path
120
+ }
108
121
 
109
- Response.parse(resp.body)
122
+ if !resp.headers['content-type'].eql?("application/json;charset=UTF-8")
123
+ fail exception('Invalid content-type error')
124
+ end
125
+
126
+ Response.parse(resp.body, path)
110
127
  rescue Faraday::Error::ConnectionFailed => e
111
128
  if e.message =~ /^SSL_connect/
112
129
  warn(*SSL_WARNING)
@@ -134,11 +151,7 @@ module Controls
134
151
  # @param [String] version the API version to collect documentation from
135
152
  def references(version = '1.0')
136
153
  version = '1.0' unless version =~ /\d.\d/
137
-
138
- web_get "/api/#{version}"
139
-
140
- # [review] - Use Response#generate_ruby
141
- @references = Hash[Response.parse(resp.body).sort]
154
+ web_get "/api/#{version}"
142
155
  rescue Faraday::Error::ConnectionFailed => e
143
156
  if e.message =~ /^SSL_connect/
144
157
  warn(*SSL_WARNING)
@@ -176,8 +189,16 @@ module Controls
176
189
  headers = connection_options[:headers].merge(headers)
177
190
  url = URI.escape(File.join(web_endpoint, path))
178
191
  resp = middleware.get(url, params, headers)
192
+ @_last_request = {
193
+ response: resp,
194
+ path: path
195
+ }
179
196
 
180
- Response.parse(resp.body)
197
+ if !resp.headers['content-type'].eql?("application/json;charset=UTF-8")
198
+ fail exception('Invalid content-type error')
199
+ end
200
+
201
+ JSON.parse(resp.body)
181
202
  rescue Faraday::Error::ConnectionFailed => e
182
203
  if e.message =~ /^SSL_connect/
183
204
  warn(*SSL_WARNING)
@@ -185,5 +206,19 @@ module Controls
185
206
  raise e
186
207
  end
187
208
  end
209
+
210
+ def exception(message = "HTTP Error")
211
+ last_request = _last_request
212
+ if last_request
213
+ message << ": #{last_request[:response].status} #{Rack::Utils::HTTP_STATUS_CODES[last_request[:response].status]} #{last_request[:path]}"
214
+ else
215
+ message = 'Unknown error'
216
+ end
217
+
218
+ Controls::Error.new(message)
219
+ end
220
+
221
+ private
222
+ attr_reader :_last_request
188
223
  end
189
224
  end
@@ -65,7 +65,6 @@ module Controls
65
65
  @middleware ||= Faraday.new(api_endpoint, connection_options) do |conn|
66
66
  conn.adapter Faraday.default_adapter
67
67
  conn.response :logger if ENV['CONTROLS_DEBUG']
68
- conn.use Controls::Response::RaiseError
69
68
  end
70
69
  end
71
70
 
@@ -0,0 +1,46 @@
1
+ module Dish
2
+ class Plate
3
+ def method_missing(method, *args, &block)
4
+ method = method.to_s
5
+ camel_case_key = method.split('_').map(&:capitalize).join
6
+ camel_case_key[0] = camel_case_key[0].downcase
7
+
8
+ if method.end_with?('?')
9
+ key = camel_case_key[0..-2]
10
+ _check_for_presence(key)
11
+ else
12
+ value = _get_value(camel_case_key)
13
+ if value.nil?
14
+ super(method.to_sym, *args, &block)
15
+ else
16
+ value
17
+ end
18
+ end
19
+ end
20
+
21
+ def methods()
22
+ valid_keys = as_hash.keys.map do |key|
23
+ key.to_s.gsub(/([^A-Z])([A-Z]+)/, '\1_\2').downcase.to_sym
24
+ end
25
+
26
+ valid_keys + super
27
+ end
28
+
29
+ def inspect
30
+ hash = as_hash
31
+ keys_to_snake_case = hash.keys.map { |key|
32
+ [key, key.to_s.gsub(/([^A-Z])([A-Z]+)/, '\1_\2').downcase]
33
+ }.to_h
34
+
35
+ vars = hash.map do |key, value|
36
+ "#{keys_to_snake_case[key]}: #{_get_value(key)}"
37
+ end
38
+
39
+ "#<#{self.class}: #{vars.join(', ')}>"
40
+ end
41
+
42
+ def to_json(*args)
43
+ as_hash.to_json(*args)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,11 @@
1
+ require 'dish'
2
+ require 'controls/ext/dish/plate'
3
+ require 'controls/objects/assessment'
4
+ require 'controls/objects/asset'
5
+ require 'controls/objects/configuration'
6
+ require 'controls/objects/guidance'
7
+ require 'controls/objects/security_control'
8
+ require 'controls/objects/security_control_coverage'
9
+ require 'controls/objects/threat'
10
+ require 'controls/objects/threat_vector'
11
+ require 'controls/objects/trend'
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class Assessment < Dish::Plate
3
+ coerce :timestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ id.to_s
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,36 @@
1
+ require 'controls/objects/security_control_finding'
2
+
3
+ module Controls
4
+ class Asset < Dish::Plate
5
+ coerce :discoveredAt, ->(value) { Time.at(value / 1000) if value }
6
+ coerce :securityControlFindings, Controls::SecurityControlFinding
7
+
8
+ def to_s
9
+ %(#{host_name} (#{ipaddress}) - #{operating_system})
10
+ end
11
+ end
12
+
13
+ class AssetCollection < Dish::Plate
14
+ coerce :resources, Asset
15
+
16
+ def map(*args, &block)
17
+ resources.map(*args, &block)
18
+ end
19
+
20
+ def first
21
+ resources.first
22
+ end
23
+
24
+ def last
25
+ resources.last
26
+ end
27
+
28
+ def [](index)
29
+ resources[index]
30
+ end
31
+
32
+ def to_s
33
+ resources.sort_by(&:ipaddress).map(&:to_s).join("\n")
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class Configuration < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ title
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class ConfigurationFinding < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ "#{state}: #{reason.strip}"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module Controls
2
+ Guidance = Class.new(Dish::Plate)
3
+ Guidance::Reference = Class.new(Dish::Plate)
4
+ Guidance::Section = Class.new(Dish::Plate)
5
+
6
+ class Guidance
7
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
8
+ coerce :references, Reference
9
+ coerce :sections, Section
10
+
11
+ def to_s
12
+ title
13
+ end
14
+ end
15
+
16
+ PrioritizedGuidance = Class.new(Guidance)
17
+ end
@@ -0,0 +1,7 @@
1
+ module Controls
2
+ class SecurityControl < Dish::Plate
3
+ def to_s
4
+ name
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class SecurityControlCoverage < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ title
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ require 'controls/objects/configuration_finding'
2
+
3
+ module Controls
4
+ class SecurityControlFinding < Dish::Plate
5
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
6
+ coerce :configurationFindings, Controls::ConfigurationFinding
7
+
8
+ def to_s
9
+ "#{security_control_name}: #{configuration_findings.map { |finding| "\n #{finding}" }.join}"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class Threat < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ title
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class ThreatVector < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ title
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Controls
2
+ class Trend < Dish::Plate
3
+ coerce :assessmentTimestamp, ->(value) { Time.at(value / 1000) if value }
4
+
5
+ def to_s
6
+ format('%05.2f', grade)
7
+ end
8
+ end
9
+ end
@@ -1,76 +1,32 @@
1
- require 'active_support/core_ext/string/inflections'
2
- require 'active_support/core_ext/hash/keys'
3
- require 'controls/response/raise_error'
1
+ require 'controls/objects'
4
2
 
5
3
  module Controls
6
- # A namespace for response related classes
4
+ # A module to encapsulate middleware customization
7
5
  module Response
8
- # @param [String] response the response body as a JSON String provided by
9
- # the ControlsInsight API
10
- # @return [Array,Hash] the response after being parsed into an Array or
11
- # Hash
12
- def self.parse(response)
13
- response = JSON.parse(response)
14
- end
6
+ def self.parse(obj, path = nil)
7
+ hash_or_array = JSON.parse(obj)
15
8
 
16
- # @param [Array,Hash] response the Array or Hash to convert into a ruby
17
- # style object
18
- def self.generate_ruby(response)
19
- if response.is_a? String
20
- response = JSON.parse(response)
9
+ if hash_or_array.is_a?(Hash) && hash_or_array.key?('message') && hash_or_array.key?('documentationUrl')
10
+ type = Controls::Error
21
11
  end
22
12
 
23
- # TODO: Determine the specific format, or create a new, recursive (w/
24
- # array support) deep method
25
- # NOTE: If the ControlsInsight API begins returning more complex JSON
26
- # this conditional must be updated.
27
- if response.is_a? Hash
28
- response.deep_transform_keys! { |key| key.underscore }
29
-
30
- if response.has_key? 'resources'
31
- response['resources'].each do |hash|
32
- hash.deep_transform_keys! { |key| key.underscore }
33
-
34
- if hash.has_key? 'security_control_findings'
35
- hash['security_control_findings'].each do |subhash|
36
- subhash.deep_transform_keys! { |key| key.underscore }
37
-
38
- if subhash.has_key? 'configuration_findings'
39
- subhash['configuration_findings'].each do |subhash_two|
40
- subhash_two.deep_transform_keys! { |key| key.underscore }
41
- end
42
- end
43
- end
44
- end
45
- end
13
+ type ||=
14
+ case path
15
+ when %r(^(?:/\d.\d)?/coverage/security_controls)
16
+ Controls::SecurityControlCoverage
17
+ when /(configuration|event|guidance|prioritized_guidance|security_control|threat_vector|trend)s?$/
18
+ Controls.const_get(Regexp.last_match[1].split('_').map(&:capitalize).join)
19
+ when %r(^(?:/\d.\d)?\/(assessment|configuration|threat|threat_vector)s)
20
+ Controls.const_get(Regexp.last_match[1].split('_').map(&:capitalize).join)
21
+ when /((?:applicable|miconfigured|uncovered|undefended)?_?asset)s$/
22
+ Controls.const_get('AssetCollection')
23
+ when %r(^/((?:applicable|miconfigured|uncovered|undefended)?_?asset)s/)
24
+ Controls.const_get('Asset')
25
+ else
26
+ Dish::Plate
46
27
  end
47
- elsif response.is_a? Array
48
- response.each do |element|
49
- if element.is_a? Hash
50
- element.deep_transform_keys! { |key| key.underscore }
51
-
52
- if element.has_key? 'resources'
53
- element['resources'].each do |hash|
54
- hash.deep_transform_keys! { |key| key.underscore }
55
-
56
- if hash.has_key? 'security_control_findings'
57
- hash['security_control_findings'].each do |subhash|
58
- subhash.deep_transform_keys! { |key| key.underscore }
59
-
60
- if subhash.has_key? 'configuration_findings'
61
- subhash['configuration_findings'].each do |subhash_two|
62
- subhash_two.deep_transform_keys! { |key| key.underscore }
63
- end
64
- end
65
- end
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end
72
28
 
73
- response
29
+ Dish(hash_or_array, type)
74
30
  end
75
31
  end
76
32
  end
@@ -1,4 +1,4 @@
1
1
  module Controls
2
2
  # The version of the Controls gem
3
- VERSION = '1.2.0'
3
+ VERSION = '1.3.0'
4
4
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: controls
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erran Carey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-04 00:00:00.000000000 Z
11
+ date: 2014-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
14
+ name: dish
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.9'
41
41
  - !ruby/object:Gem::Dependency
42
- name: nokogiri
42
+ name: rack
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -175,9 +175,20 @@ files:
175
175
  - lib/controls/client/trends.rb
176
176
  - lib/controls/configurable.rb
177
177
  - lib/controls/default.rb
178
- - lib/controls/error.rb
178
+ - lib/controls/ext/dish/plate.rb
179
+ - lib/controls/objects.rb
180
+ - lib/controls/objects/assessment.rb
181
+ - lib/controls/objects/asset.rb
182
+ - lib/controls/objects/configuration.rb
183
+ - lib/controls/objects/configuration_finding.rb
184
+ - lib/controls/objects/guidance.rb
185
+ - lib/controls/objects/security_control.rb
186
+ - lib/controls/objects/security_control_coverage.rb
187
+ - lib/controls/objects/security_control_finding.rb
188
+ - lib/controls/objects/threat.rb
189
+ - lib/controls/objects/threat_vector.rb
190
+ - lib/controls/objects/trend.rb
179
191
  - lib/controls/response.rb
180
- - lib/controls/response/raise_error.rb
181
192
  - lib/controls/version.rb
182
193
  - spec/controls_spec.rb
183
194
  - spec/helper.rb
@@ -1,132 +0,0 @@
1
- module Controls
2
- # A namespace for errors in the Controls module
3
- class Error < StandardError
4
- # @!attribute [r] error_message
5
- # @return [String] the error message
6
- # @!attribute [r] error_status
7
- # @return [Fixnum] the error message
8
- # @!attribute [r] error_json
9
- # @return [Hash] the JSON body from the error message
10
- attr_reader :error_json
11
- attr_reader :error_message
12
- attr_reader :error_status
13
-
14
- # @raise [BadRequest,Unauthorized,NotFound,InternalServerError] a subclass
15
- # of {Controls::Error}
16
- # @return [nil] if no error was raised
17
- def self.from_response(response)
18
- error = case response[:status].to_i
19
- when 302
20
- # TODO: Nexpose/ControlsInsight returns 302 when you either visit a
21
- # none existant path (Nexpose) or unauthenticated
22
- # (ControlsInsight).
23
- Found # if response[:body].empty?
24
- when 400 then BadRequest
25
- when 401 then Unauthorized
26
- when 404 then NotFound
27
- when 500 then InternalServerError
28
- end
29
-
30
- error.new(response) if error
31
- end
32
-
33
- # @return [self] generates an error and passes it to super
34
- def initialize(response = nil)
35
- @response = response
36
- super(generate_error)
37
- end
38
-
39
- private
40
-
41
- # @return [String] an error message to be used by {#generate_error}
42
- def response_message
43
- return @response_message if @response_message
44
-
45
- resp = @response[:response]
46
-
47
- if resp.headers['content-type']
48
- resp.headers['content-type'][/(\S+);charset=utf-8/i]
49
- html = Regexp.last_match && Regexp.last_match[1].eql?('text/html')
50
- end
51
-
52
- @response_message = if html
53
- doc = Nokogiri::XML.parse(resp.body)
54
-
55
- if doc.css('title').text.eql? 'ControlsInsight'
56
- message = ['message'].zip(doc.css('h1').map(&:text))
57
- reason = ['reason'].zip([doc.css('p').map(&:text)])
58
- Hash[message + reason]
59
- else
60
- Hash[doc.css('HR').children.map { |elem| elem.text.split(' ', 2) }]
61
- end
62
- else
63
- if resp.body.empty?
64
- @error_json = {}
65
- else
66
- @error_json = JSON.parse(resp.body)
67
- @error_message = @error_json['message']
68
- @error_status = @error_json['status'].to_i
69
-
70
- @error_json
71
- end
72
- end
73
- end
74
-
75
- # @return [String] the error message passed to super on {#initialize}
76
- def generate_error
77
- return unless @response
78
-
79
- message = "#{@response[:method]} ".upcase
80
- message << "#{@response[:url].path}"
81
-
82
- if response_message.is_a? Hash
83
- message << ": #{response_message['message']}\n" if response_message['message']
84
-
85
- if response_message['reason'].respond_to?(:join)
86
- message << response_message['reason'].join("\n")
87
- elsif response_message['reason']
88
- message << response_message['reason'].to_s
89
- end
90
- elsif response_message.is_a? String
91
- message << response_message
92
- else
93
- message << "#{@response[:status]} -"
94
- message << self.class.to_s.split('::', 2).last
95
- end
96
-
97
- message.strip
98
- end
99
- end
100
-
101
- # @!group Generic errors
102
-
103
- # TODO REVIEW: To be raised when a user hasn't explicitly supplied credentials or set up
104
- # any environment defaults.
105
- Unauthenticated = Class.new(StandardError)
106
-
107
- # @!endgroup
108
-
109
- # @!group HTTP errors
110
-
111
- # @return [Found] an error to be raised when a status code of 401 is
112
- # returned by the API
113
- Found = Class.new(Error)
114
-
115
- # @return [Unauthorized] an error to be raised when a status code of 401 is
116
- # returned by the API
117
- Unauthorized = Class.new(Error)
118
-
119
- # @return [BadRequest] an error to be raised when a status code of 400 is
120
- # returned by the API
121
- BadRequest = Class.new(Error)
122
-
123
- # @return [NotFound] an error to be raised when a status code of 404 is
124
- # returned by the API
125
- NotFound = Class.new(Error)
126
-
127
- # @return [InternalServerError] an error to be raised when a status code of
128
- # 500 is returned by the API
129
- InternalServerError = Class.new(Error)
130
-
131
- # @!endgroup
132
- end
@@ -1,21 +0,0 @@
1
- require 'controls/error'
2
-
3
- module Controls
4
- module Response
5
- # A middleware plugin that hooks into the Faraday client used by this gem
6
- class RaiseError < Faraday::Response::Middleware
7
- private
8
-
9
- # Implements the {#on_complete} hook used by Faraday's middleware
10
- #
11
- # @raise [Controls::Error] a subclass of Controls::Error if any errors
12
- # were encountered
13
- # @return [nil] if no error was found
14
- def on_complete(response)
15
- if error = Controls::Error.from_response(response)
16
- raise error
17
- end
18
- end
19
- end
20
- end
21
- end