onfido 1.1.0 → 2.1.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.
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