onfido 1.1.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/gem-push.yml +31 -0
  3. data/.github/workflows/ruby.yml +25 -0
  4. data/.rubocop.yml +5 -49
  5. data/.travis.yml +2 -8
  6. data/CHANGELOG.md +26 -1
  7. data/Gemfile +2 -0
  8. data/README.md +37 -148
  9. data/lib/onfido.rb +3 -3
  10. data/lib/onfido/api.rb +18 -12
  11. data/lib/onfido/errors/connection_error.rb +2 -0
  12. data/lib/onfido/errors/onfido_error.rb +2 -0
  13. data/lib/onfido/errors/request_error.rb +2 -0
  14. data/lib/onfido/errors/server_error.rb +2 -0
  15. data/lib/onfido/options.rb +38 -0
  16. data/lib/onfido/resource.rb +48 -59
  17. data/lib/onfido/resources/address.rb +3 -4
  18. data/lib/onfido/resources/applicant.rb +2 -0
  19. data/lib/onfido/resources/check.rb +6 -0
  20. data/lib/onfido/resources/document.rb +2 -0
  21. data/lib/onfido/resources/extraction.rb +2 -0
  22. data/lib/onfido/resources/live_photo.rb +2 -0
  23. data/lib/onfido/resources/live_video.rb +2 -0
  24. data/lib/onfido/resources/report.rb +2 -0
  25. data/lib/onfido/resources/sdk_token.rb +2 -0
  26. data/lib/onfido/resources/webhook.rb +4 -2
  27. data/lib/onfido/version.rb +3 -1
  28. data/onfido.gemspec +5 -6
  29. data/spec/integrations/address_spec.rb +4 -2
  30. data/spec/integrations/applicant_spec.rb +12 -7
  31. data/spec/integrations/check_spec.rb +17 -4
  32. data/spec/integrations/document_spec.rb +7 -3
  33. data/spec/integrations/extraction_spec.rb +6 -2
  34. data/spec/integrations/live_photo_spec.rb +7 -3
  35. data/spec/integrations/live_video_spec.rb +6 -1
  36. data/spec/integrations/report_spec.rb +6 -1
  37. data/spec/integrations/resource_spec.rb +106 -0
  38. data/spec/integrations/sdk_token_spec.rb +5 -1
  39. data/spec/integrations/webhook_spec.rb +28 -24
  40. data/spec/onfido/api_spec.rb +14 -25
  41. data/spec/onfido/connection_error_spec.rb +4 -2
  42. data/spec/onfido/options_spec.rb +39 -0
  43. data/spec/onfido/request_error_spec.rb +4 -2
  44. data/spec/spec_helper.rb +3 -5
  45. data/spec/support/fake_onfido_api.rb +63 -49
  46. data/spec/support/fixtures/applicant.json +1 -1
  47. data/spec/support/fixtures/check.json +1 -1
  48. data/spec/support/fixtures/checks.json +1 -1
  49. data/spec/support/fixtures/document.json +1 -1
  50. data/spec/support/fixtures/documents.json +2 -2
  51. data/spec/support/fixtures/live_photo.json +2 -2
  52. data/spec/support/fixtures/live_photos.json +4 -4
  53. data/spec/support/fixtures/live_video.json +2 -2
  54. data/spec/support/fixtures/live_videos.json +2 -2
  55. data/spec/support/fixtures/report.json +1 -1
  56. data/spec/support/fixtures/reports.json +2 -2
  57. data/spec/support/fixtures/webhook.json +1 -1
  58. data/spec/support/fixtures/webhooks.json +2 -2
  59. metadata +16 -33
  60. data/Rakefile +0 -1
  61. data/lib/onfido/configuration.rb +0 -47
  62. data/lib/onfido/null_logger.rb +0 -5
  63. data/spec/integrations/exceptions_spec.rb +0 -73
  64. data/spec/onfido/resource_spec.rb +0 -133
  65. data/spec/onfido_spec.rb +0 -83
data/lib/onfido/api.rb CHANGED
@@ -1,47 +1,53 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class API
3
- def initialize(options = {})
4
- @api_key = options[:api_key]
5
+ def initialize(api_key:, region:, **extra_options)
6
+ @options = Onfido::Options.new(api_key: api_key, region: region, **extra_options)
5
7
  end
6
8
 
7
9
  def applicant
8
- Onfido::Applicant.new(@api_key)
10
+ @applicant ||= Onfido::Applicant.new(options)
9
11
  end
10
12
 
11
13
  def check
12
- Onfido::Check.new(@api_key)
14
+ @check ||= Onfido::Check.new(options)
13
15
  end
14
16
 
15
17
  def document
16
- Onfido::Document.new(@api_key)
18
+ @document ||= Onfido::Document.new(options)
17
19
  end
18
20
 
19
21
  def live_photo
20
- Onfido::LivePhoto.new(@api_key)
22
+ @live_photo ||= Onfido::LivePhoto.new(options)
21
23
  end
22
24
 
23
25
  def live_video
24
- Onfido::LiveVideo.new(@api_key)
26
+ @live_video ||= Onfido::LiveVideo.new(options)
25
27
  end
26
28
 
27
29
  def report
28
- Onfido::Report.new(@api_key)
30
+ @report ||= Onfido::Report.new(options)
29
31
  end
30
32
 
31
33
  def sdk_token
32
- Onfido::SdkToken.new(@api_key)
34
+ @sdk_token ||= Onfido::SdkToken.new(options)
33
35
  end
34
36
 
35
37
  def webhook
36
- Onfido::Webhook.new(@api_key)
38
+ @webhook ||= Onfido::Webhook.new(options)
37
39
  end
38
40
 
39
41
  def address
40
- Onfido::Address.new(@api_key)
42
+ @address ||= Onfido::Address.new(options)
41
43
  end
42
44
 
43
45
  def extraction
44
- Onfido::Extraction.new(@api_key)
46
+ @extraction ||= Onfido::Extraction.new(options)
45
47
  end
48
+
49
+ private
50
+
51
+ attr_reader :options
46
52
  end
47
53
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class ConnectionError < OnfidoError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class OnfidoError < StandardError
3
5
  attr_accessor :response_code, :response_body
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class RequestError < OnfidoError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class ServerError < OnfidoError
3
5
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Onfido
4
+ class Options
5
+ REGIONS = %w[eu us ca].freeze
6
+
7
+ def initialize(api_key:, region:, open_timeout: 10, read_timeout: 30, unknown_api_url: nil)
8
+ @api_key = api_key
9
+ @region = region.to_s.downcase
10
+ @open_timeout = open_timeout
11
+ @read_timeout = read_timeout
12
+ @unknown_api_url = unknown_api_url
13
+
14
+ raise "Unknown region #{@region}" unless REGIONS.include?(@region)
15
+ end
16
+
17
+ def rest_client
18
+ @rest_client ||= RestClient::Resource.new(
19
+ base_url,
20
+ read_timeout: read_timeout,
21
+ open_timeout: open_timeout,
22
+ headers: {
23
+ 'Authorization' => "Token token=#{api_key}",
24
+ 'Accept' => 'application/json',
25
+ 'User-Agent' => "onfido-ruby/#{Onfido::VERSION}"
26
+ }
27
+ )
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :api_key, :open_timeout, :read_timeout
33
+
34
+ def base_url
35
+ @unknown_api_url || "https://api.#{@region}.onfido.com/v3.2/"
36
+ end
37
+ end
38
+ end
@@ -1,55 +1,52 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
- class Resource
3
- VALID_HTTP_METHODS = %i(get post put delete).freeze
4
+ class Resource # rubocop:todo Metrics/ClassLength
5
+ VALID_HTTP_METHODS = %i[get post put delete].freeze
4
6
  REQUEST_TIMEOUT_HTTP_CODE = 408
5
7
 
6
- def initialize(api_key = nil)
7
- @api_key = api_key || Onfido.api_key
8
+ def initialize(options)
9
+ @rest_client = options.rest_client
8
10
  end
9
11
 
10
- VALID_HTTP_METHODS.each do |method|
11
- define_method method do |*args|
12
- make_request(
13
- method: method.to_sym,
14
- url: Onfido.endpoint + args.first.fetch(:path),
15
- payload: build_query(args.first.fetch(:payload, {}))
16
- )
17
- end
12
+ private
13
+
14
+ attr_reader :rest_client
15
+
16
+ def get(path:)
17
+ handle_request { rest_client[path].get }
18
18
  end
19
19
 
20
- private
20
+ def post(path:, payload: nil)
21
+ handle_request { rest_client[path].post(payload) }
22
+ end
21
23
 
22
- def make_request(options)
23
- url = options.fetch(:url)
24
- payload = options.fetch(:payload)
25
- method = options.fetch(:method)
24
+ def put(path:, payload: nil)
25
+ handle_request { rest_client[path].put(payload) }
26
+ end
26
27
 
27
- request_options = {
28
- url: url,
29
- payload: payload,
30
- method: method,
31
- headers: headers,
32
- open_timeout: Onfido.open_timeout,
33
- timeout: Onfido.read_timeout
34
- }
28
+ def delete(path:)
29
+ handle_request { rest_client[path].delete }
30
+ end
35
31
 
36
- response = RestClient::Request.execute(request_options)
32
+ def handle_request
33
+ response = yield
37
34
 
38
35
  # response should be parsed only when there is a response expected
39
36
  parse(response) unless response.code == 204 # no_content
40
- rescue RestClient::ExceptionWithResponse => error
41
- if error.response && !timeout_response?(error.response)
42
- handle_api_error(error.response)
37
+ rescue RestClient::ExceptionWithResponse => e
38
+ if e.response && !timeout_response?(e.response)
39
+ handle_api_error(e.response)
43
40
  else
44
- handle_restclient_error(error, url)
41
+ handle_restclient_error(e)
45
42
  end
46
- rescue RestClient::Exception, Errno::ECONNREFUSED => error
47
- handle_restclient_error(error, url)
43
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
44
+ handle_restclient_error(e)
48
45
  end
49
46
 
50
47
  def parse(response)
51
48
  content_type = response.headers[:content_type]
52
- if content_type && content_type.include?("application/json")
49
+ if content_type&.include?('application/json')
53
50
  JSON.parse(response.body.to_s)
54
51
  else
55
52
  response.body
@@ -62,14 +59,6 @@ module Onfido
62
59
  response.code.to_i == REQUEST_TIMEOUT_HTTP_CODE
63
60
  end
64
61
 
65
- def headers
66
- {
67
- 'Authorization' => "Token token=#{@api_key}",
68
- 'Accept' => "application/json",
69
- 'User-Agent' => "onfido-ruby/#{Onfido::VERSION}"
70
- }
71
- end
72
-
73
62
  # There seems to be a serialization issue with the HTTP client
74
63
  # which does not serialize the payload properly.
75
64
  # Have a look here https://gist.github.com/PericlesTheo/cb35139c57107ab3c84a
@@ -85,12 +74,12 @@ module Onfido
85
74
  def handle_api_error(response)
86
75
  parsed_response = parse(response)
87
76
 
88
- general_api_error(response.code, response.body) unless parsed_response["error"]
77
+ general_api_error(response.code, response.body) unless parsed_response['error']
89
78
 
90
79
  error_class = response.code.to_i >= 500 ? ServerError : RequestError
91
80
 
92
81
  raise error_class.new(
93
- parsed_response["error"]['message'],
82
+ parsed_response['error']['message'],
94
83
  response_code: response.code,
95
84
  response_body: response.body
96
85
  )
@@ -107,46 +96,46 @@ module Onfido
107
96
  )
108
97
  end
109
98
 
110
- def handle_restclient_error(error, url)
99
+ def handle_restclient_error(error) # rubocop:todo Metrics/MethodLength
111
100
  connection_message =
112
- "Please check your internet connection and try again. " \
113
- "If this problem persists, you should let us know at info@onfido.com."
101
+ 'Please check your internet connection and try again. ' \
102
+ 'If this problem persists, you should let us know at info@onfido.com.'
114
103
 
115
104
  message =
116
105
  case error
117
106
  when RestClient::RequestTimeout
118
- "Could not connect to Onfido (#{url}). #{connection_message}"
107
+ "Could not connect to Onfido . #{connection_message}"
119
108
 
120
109
  when RestClient::ServerBrokeConnection
121
- "The connection to the server (#{url}) broke before the " \
122
- "request completed. #{connection_message}"
110
+ "The connection to the server broke before the request completed. #{connection_message}"
123
111
 
124
112
  when RestClient::SSLCertificateNotVerified
125
113
  "Could not verify Onfido's SSL certificate. Please make sure " \
126
- "that your network is not intercepting certificates. " \
127
- "(Try going to #{Onfido.endpoint} in your browser.) " \
128
- "If this problem persists, let us know at info@onfido.com."
114
+ 'that your network is not intercepting certificates. '
115
+
116
+ when RestClient::BadGateway
117
+ "Could not connect to Onfido. Server may be overloaded." \
129
118
 
130
119
  when SocketError
131
- "Unexpected error when trying to connect to Onfido. " \
132
- "You may be seeing this message because your DNS is not working. " \
120
+ 'Unexpected error when trying to connect to Onfido. ' \
121
+ 'You may be seeing this message because your DNS is not working. ' \
133
122
  "To check, try running 'host onfido.com' from the command line."
134
123
 
135
124
  else
136
- "Unexpected error communicating with Onfido. " \
137
- "If this problem persists, let us know at info@onfido.com."
125
+ 'Unexpected error communicating with Onfido. ' \
126
+ 'If this problem persists, let us know at info@onfido.com.'
138
127
  end
139
128
 
140
129
  full_message = message + "\n\n(Network error: #{error.message})"
141
130
 
142
- raise ConnectionError.new(full_message)
131
+ raise ConnectionError, full_message
143
132
  end
144
133
 
145
134
  def validate_file!(file)
146
135
  return if file.respond_to?(:read) && file.respond_to?(:path)
147
136
 
148
- raise ArgumentError, "File must be a `File`-like object which responds to " \
149
- "`#read` and `#path`"
137
+ raise ArgumentError, 'File must be a `File`-like object which responds to ' \
138
+ '`#read` and `#path`'
150
139
  end
151
140
  end
152
141
  end
@@ -1,10 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class Address < Resource
3
5
  def all(postcode)
4
- get(
5
- path: 'addresses/pick',
6
- payload: { postcode: postcode.delete(' ') }
7
- )
6
+ get(path: "addresses/pick?postcode=#{postcode.delete(' ')}")
8
7
  end
9
8
  end
10
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class Applicant < Resource
3
5
  def create(payload)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class Check < Resource
3
5
  def create(applicant_id:, report_names:, **payload)
@@ -18,5 +20,9 @@ module Onfido
18
20
  def resume(check_id)
19
21
  post(path: "checks/#{check_id}/resume")
20
22
  end
23
+
24
+ def download(check_id)
25
+ get(path: "checks/#{check_id}/download")
26
+ end
21
27
  end
22
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class Document < Resource
3
5
  # with open-uri the file can be a link or an actual file
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class Extraction < Resource
3
5
  def create(document_id:)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class LivePhoto < Resource
3
5
  # with open-uri the file can be a link or an actual file
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class LiveVideo < Resource
3
5
  def find(live_video_id)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class Report < Resource
3
5
  def find(report_id)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class SdkToken < Resource
3
5
  def create(applicant_id:, **payload)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class Webhook < Resource
3
5
  def create(url:, **payload)
@@ -22,8 +24,8 @@ module Onfido
22
24
  # request to one computed from the body
23
25
  def self.valid?(request_body, request_signature, token)
24
26
  if [request_body, request_signature, token].any?(&:nil?)
25
- raise ArgumentError, "A request body, request signature and token " \
26
- "must be provided"
27
+ raise ArgumentError, 'A request body, request signature and token ' \
28
+ 'must be provided'
27
29
  end
28
30
 
29
31
  computed_signature = generate_signature(request_body, token)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
- VERSION = '1.1.0'.freeze
4
+ VERSION = '2.1.0'
3
5
  end
data/onfido.gemspec CHANGED
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
@@ -12,8 +12,8 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = 'A wrapper for Onfido API'
13
13
  spec.description = "A thin wrapper for Onfido's API. This gem only supports "\
14
14
  "v3 of the Onfido API. Refer to Onfido's "\
15
- "API documentation for details of the expected "\
16
- "requests and responses."
15
+ 'API documentation for details of the expected '\
16
+ 'requests and responses.'
17
17
  spec.homepage = 'http://github.com/onfido/onfido-ruby'
18
18
  spec.license = 'MIT'
19
19
 
@@ -21,12 +21,11 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
23
  spec.require_paths = ['lib']
24
- spec.required_ruby_version = ">= 2.2.0"
24
+ spec.required_ruby_version = '>= 2.4.0'
25
25
 
26
- spec.add_development_dependency 'rake', '~> 12.0'
27
26
  spec.add_development_dependency 'rspec', '~> 3.1'
28
27
  spec.add_development_dependency 'rspec-its', '~> 1.2'
29
- spec.add_development_dependency 'rubocop', '~> 0.57.0'
28
+ spec.add_development_dependency 'rubocop', '~> 1.11'
30
29
  spec.add_development_dependency 'sinatra', '~> 1.4'
31
30
  spec.add_development_dependency 'webmock', '~> 3.0'
32
31