signifyd 0.1.5

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.
@@ -0,0 +1,387 @@
1
+ # External Dependencies
2
+ require 'i18n'
3
+ require 'set'
4
+ require 'active_support'
5
+ require 'rest_client'
6
+ require 'uri'
7
+ require 'json'
8
+ require 'base64'
9
+ require 'openssl'
10
+
11
+ # Gem Version
12
+ require 'signifyd/version'
13
+
14
+ # API operations
15
+ require 'signifyd/util'
16
+ require 'signifyd/signifyd_object'
17
+ require 'signifyd/resource'
18
+ require 'signifyd/api/create'
19
+ require 'signifyd/api/list'
20
+ require 'signifyd/api/update'
21
+ require 'signifyd/case'
22
+
23
+ # Internal Dependencies
24
+ require 'signifyd/errors/signifyd_error'
25
+ require 'signifyd/errors/api_error'
26
+ require 'signifyd/errors/api_connection_error'
27
+ require 'signifyd/errors/authentication_error'
28
+ require 'signifyd/errors/invalid_request_error'
29
+ require 'signifyd/errors/not_implemented_error'
30
+
31
+ module Signifyd
32
+ # ssl_bundle_path
33
+ #
34
+ # Path to hold Signifyd.com's certificate
35
+ # @return: String[path to certificate file]
36
+ @@ssl_bundle_path = File.join(File.dirname(__FILE__), 'data/ca-certificates.crt')
37
+
38
+ # api_key
39
+ #
40
+ # Default point for where the application will hold the API_KEY
41
+ # for the current instance. If not set, must be passed in all calls
42
+ # as last parameter.
43
+ # @return String[unique identifier]
44
+ @@api_key = nil
45
+
46
+ # api_base
47
+ #
48
+ # Root url where the Signifyd API endpoints will live. This can be
49
+ # changed by setting Signifyd.test_mode = true and will default to
50
+ # staging env.
51
+ # @return: String[url to Signifyd's API]
52
+ @@api_base = 'https://api.signifyd.com'
53
+
54
+ # api_version
55
+ #
56
+ # Version right now will be the url structure, might change later.
57
+ # For now this is ok.
58
+ # @return: String[url path of our current api version]
59
+ @@api_version = '/v2'
60
+
61
+ # verify_ssl_certs
62
+ #
63
+ # When this is set to false, any request made will not be a verfied
64
+ # and supported request by Signifyd. This should be set to true and
65
+ # the library will use the Signifyd keys..not for now :/
66
+ # @return: Boolean
67
+ @@verify_ssl_certs = true
68
+
69
+ # test_mode
70
+ #
71
+ # When set to true, will default to Signifyd's staging environment.
72
+ # This as well should always be set to false.
73
+ # @return: Boolean
74
+ @@test_mode = false
75
+
76
+ # local_mode
77
+ #
78
+ # When set to true, will default to a local environment of localhost:9000.
79
+ # This as well should always be set to false.
80
+ # @return: Boolean
81
+ @@local_mode = false
82
+
83
+ # ssl_bundle_path
84
+ #
85
+ # Returns the path to the certificate store location
86
+ def self.ssl_bundle_path
87
+ @@ssl_bundle_path
88
+ end
89
+
90
+ # api_url
91
+ #
92
+ # This method is used to set the full url that the request will be made
93
+ # to. Ideally, pass in the version of the API and then the method that
94
+ # will be requested.
95
+ # An example retrun would be: 'https://signifyd.com/v2/cases
96
+ # @return: String[url for request to be made]
97
+ def self.api_url(url='')
98
+ @@api_base + url
99
+ end
100
+
101
+ # api_key=
102
+ #
103
+ # Setter method to set the API key. Set into class variable and used
104
+ # globally on all calls made.
105
+ # @return: String[api key]
106
+ def self.api_key=(api_key)
107
+ @@api_key = api_key
108
+ end
109
+
110
+ # api_key
111
+ #
112
+ # Getter method for the API key that has been set by the application.
113
+ # @return: String[api key]
114
+ def self.api_key
115
+ @@api_key
116
+ end
117
+
118
+ # api_version=
119
+ #
120
+ # Setter method to set the API version. Set into class variable and used
121
+ # globally on all calls made.
122
+ # @return: String[api url version]
123
+ def self.api_version=(api_version)
124
+ @@api_version = api_version
125
+ end
126
+
127
+ # api_version
128
+ #
129
+ # Getter method for the API version that has been set by the application.
130
+ # @return: String[api url version]
131
+ def self.api_version
132
+ @@api_version
133
+ end
134
+
135
+ # api_base=
136
+ #
137
+ # Setter method to set the API url base. Set into class variable and used
138
+ # globally on all calls made.
139
+ # @return: String[api base]
140
+ def self.api_base=(api_base)
141
+ @@api_base = api_base
142
+ end
143
+
144
+ # api_base
145
+ #
146
+ # Getter method for the API base that has been set by the application.
147
+ # @return: String[api base]
148
+ def self.api_base
149
+ @@api_base
150
+ end
151
+
152
+ # verify_ssl_certs=
153
+ #
154
+ # Setter method to set the API verify_ssl_certs. Set into class variable and
155
+ # used globally on all calls made.
156
+ # @return: Boolean
157
+ def self.verify_ssl_certs=(verify)
158
+ @@verify_ssl_certs = verify
159
+ end
160
+
161
+ # verify_ssl_certs
162
+ #
163
+ # Getter method for the API verify_ssl_certs that has been set by the application.
164
+ # @return: Boolean
165
+ def self.verify_ssl_certs
166
+ @@verify_ssl_certs
167
+ end
168
+
169
+ # test_mode=
170
+ #
171
+ # Setter method to set the API test_mode. Set into class variable and used
172
+ # globally on all calls made.
173
+ # @return: Boolean
174
+ def self.test_mode=(test_mode)
175
+ Signifyd.api_base = 'https://staging.signifyd.com' if test_mode && !self.local_mode
176
+ @@test_mode = test_mode
177
+ end
178
+
179
+ # test_mode
180
+ #
181
+ # Getter method for the API test_mode that has been set by the application.
182
+ # @return: Boolean
183
+ def self.test_mode
184
+ @@test_mode
185
+ end
186
+
187
+ # local_mode=
188
+ #
189
+ # Setter method to set the API local_mode. Set into class variable and used
190
+ # globally on all calls made.
191
+ # @return: Boolean
192
+ def self.local_mode=(local_mode)
193
+ Signifyd.api_base = 'http://localhost:9000' if local_mode && !self.test_mode
194
+ @@local_mode = local_mode
195
+ end
196
+
197
+ # local_mode
198
+ #
199
+ # Getter method for the API test_mode that has been set by the application.
200
+ # @return: Boolean
201
+ def self.local_mode
202
+ @@local_mode
203
+ end
204
+
205
+ # request
206
+ #
207
+ # Global method that will use RestClient to make all requests. Everything else
208
+ # is set between Signifyd.{setter} methods. This method is called from other
209
+ # methods so direct calls won't be necessary.
210
+ #
211
+ # @param[Req]: String[method] - :get, :post, :put, :delete
212
+ # @param[Req]: String[url] - '/cases'
213
+ # @param[Req]: Hash[params] - {transaction...}
214
+ # @param[Opt]: String[api_key] - 'YOUR-API-KEY'
215
+ # @param[Opt]: Hash[options] - optional parameters
216
+ # @return: Hash - containing response code, body, and other data
217
+ def self.request(method, url, params={}, api_key=nil, options={})
218
+ api_key = api_key.nil? ? @@api_key : api_key
219
+ raise AuthenticationError.new('No API key provided. Fix: Signifyd.api_key = \'Your API KEY\'') unless api_key
220
+
221
+ uname = (@@uname ||= RUBY_PLATFORM =~ /linux|darwin/i ? `uname -a 2>/dev/null`.strip : nil)
222
+ lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
223
+ ua = {
224
+ :bindings_version => Signifyd::VERSION,
225
+ :lang => 'ruby',
226
+ :lang_version => lang_version,
227
+ :platform => RUBY_PLATFORM,
228
+ :publisher => 'signifyd',
229
+ :uname => uname
230
+ }
231
+
232
+ if @@verify_ssl_certs
233
+ ssl_opts = {
234
+ :verify_ssl => OpenSSL::SSL::VERIFY_PEER,
235
+ :ssl_ca_file => @@ssl_bundle_path
236
+ }
237
+ else
238
+ ssl_opts = {
239
+ :verify_ssl => OpenSSL::SSL::VERIFY_NONE
240
+ }
241
+ end
242
+
243
+ # Determine how to send the data and encode it based on what method we are sending. Some
244
+ # are necessary, some are not.
245
+ case method.to_s
246
+ when 'get'
247
+ if options.has_key?(:order_id)
248
+ url = url.gsub('cases', "orders/#{options[:order_id]}/case")
249
+ end
250
+ when 'post'
251
+
252
+ when 'put'
253
+ # we need to eject out the case_id from the params hash and append it to the url
254
+ if params.has_key?(:case_id) || params.has_key?('case_id')
255
+ case_id = params.delete(:case_id)
256
+ params.reject! { |k| k == :case_id || k == 'case_id' }
257
+ url << "/#{case_id}"
258
+ end
259
+ when 'delete'
260
+
261
+ end
262
+
263
+ # Create the full url here
264
+ url = self.api_url(url)
265
+
266
+ # Parse into valid json
267
+ payload = JSON.dump(params)
268
+
269
+ # Convert the key
270
+ authkey = api_key == {} || api_key == nil ? '' : Base64.encode64(api_key)
271
+
272
+ # Headers must contain these keys
273
+ headers = {
274
+ "Content-Length" => payload.size,
275
+ "Content-Type" => "application/json",
276
+ "Authorization" => "Basic #{authkey}",
277
+ 'User-Agent' => "Signifyd Ruby #{@@api_version.gsub('/', '')}"
278
+ }
279
+
280
+ # All necessary options must be set
281
+ opts = {
282
+ :method => method,
283
+ :url => url,
284
+ :headers => headers,
285
+ :open_timeout => 30,
286
+ :payload => payload,
287
+ :timeout => 80
288
+ }.merge(ssl_opts)
289
+
290
+ # Make the request
291
+ begin
292
+ response = execute_request(opts)
293
+ rescue SocketError => e
294
+ self.handle_restclient_error(e)
295
+ rescue NoMethodError => e
296
+ if e.message =~ /\WRequestFailed\W/
297
+ e = APIConnectionError.new('Unexpected HTTP response code')
298
+ self.handle_restclient_error(e)
299
+ else
300
+ raise
301
+ end
302
+ rescue RestClient::ExceptionWithResponse => e
303
+ if rcode = e.http_code and rbody = e.http_body
304
+ self.handle_api_error(rcode, rbody)
305
+ else
306
+ self.handle_restclient_error(e)
307
+ end
308
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
309
+ self.handle_restclient_error(e)
310
+ end
311
+
312
+ rbody = response.body
313
+ rcode = response.code
314
+ return {code: rcode, body: JSON.parse(rbody)}
315
+ end
316
+
317
+ # execute_request
318
+ #
319
+ # Handles the request, pass in opts hash, RestClient makes the call.
320
+ # @param: Hash[opts] - Configured options from Signifyd.request method.
321
+ # @return: RestClient::Request - the result of the request.
322
+ def self.execute_request(opts)
323
+ RestClient::Request.execute(opts)
324
+ end
325
+
326
+ # handle_restclient_error
327
+ #
328
+ # @param: RestClient[error] - could be many different types of errors.
329
+ # @return: String[error message]
330
+ def self.handle_restclient_error(e)
331
+ case e
332
+ when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
333
+ message = "Could not connect to Signifyd (#{@@api_base}). Please check your internet connection and try again."
334
+ when RestClient::SSLCertificateNotVerified
335
+ message = "Could not verify Signifyd's SSL certificate. Please make sure that your network is not intercepting certificates. (Try going to https://api.signifyd.com/v2 in your browser.) If this problem persists, let us know at support@signifyd.com."
336
+ when SocketError
337
+ message = "Unexpected error communicating when trying to connect to Signifyd. HINT: You may be seeing this message because your DNS is not working. To check, try running 'host signifyd.com' from the command line."
338
+ else
339
+ message = "Unexpected error communicating with Signifyd. If this problem persists, let us know at support@signifyd.com."
340
+ end
341
+ message += "\n\n(Network error: #{e.message})"
342
+ raise APIConnectionError.new(message)
343
+ end
344
+
345
+ # handle_api_error
346
+ #
347
+ # @param: String
348
+ # @param: String
349
+ def self.handle_api_error(rcode, rbody)
350
+ error = {}
351
+ case rcode
352
+ when 400, 404
353
+ error[:message] = "Invalid request"
354
+ error[:param] = ""
355
+ raise invalid_request_error error, rcode, rbody
356
+ when 401
357
+ error[:message] = "Authentication error"
358
+ error[:param] = ""
359
+ raise authentication_error error, rcode, rbody
360
+ else
361
+ error[:message] = "API error"
362
+ error[:param] = ""
363
+ raise general_api_error rcode, rbody
364
+ end
365
+ end
366
+
367
+ def self.invalid_request_error(error, rcode, rbody)
368
+ raise InvalidRequestError.new(error[:message], error[:param], rcode, rbody)
369
+ end
370
+
371
+ def self.authentication_error(error, rcode, rbody)
372
+ raise AuthenticationError.new(error[:message], error[:param], rcode, rbody)
373
+ end
374
+
375
+ def self.general_api_error(rcode, rbody)
376
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
377
+ end
378
+
379
+ private
380
+ # configured?
381
+ #
382
+ # Check to see if the API key has been set
383
+ # @return: Boolean
384
+ def self.configured?
385
+ !!@@api_key
386
+ end
387
+ end
@@ -0,0 +1,16 @@
1
+ module Signifyd
2
+ module API
3
+ module Create
4
+ module ClassMethods
5
+ def create(params={}, api_key=nil)
6
+ raise InvalidRequestError.new('You have passed invalid parameters to Case.create') if params == {}
7
+ Signifyd.request(:post, self.url, params, api_key)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ module Signifyd
2
+ module API
3
+ module List
4
+ module ClassMethods
5
+ def all(filters={}, api_key=nil)
6
+ Signifyd.request(:get, url, {}, api_key, filters)
7
+ end
8
+ # To retrieve case by orderId pass in {order_id: value}
9
+ # into options
10
+ def find(options={}, filters={},api_key=nil)
11
+ Signifyd.request(:get, url, filters, api_key, options)
12
+ end
13
+ end
14
+
15
+ def self.included(base)
16
+ base.extend(ClassMethods)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ module Signifyd
2
+ module API
3
+ module Update
4
+ module ClassMethods
5
+ def update(case_id, params={}, api_key=nil)
6
+ raise InvalidRequestError.new('You have passed invalid parameters to Case.create') if params == {} || case_id.nil?
7
+ Signifyd.request(:put, self.url, params.merge(case_id: case_id), api_key)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ module Signifyd
2
+ class Case < Resource
3
+ include Signifyd::API::Create
4
+ include Signifyd::API::List
5
+ include Signifyd::API::Update
6
+ end
7
+ end