onfido 1.1.1 → 2.0.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -49
  3. data/.travis.yml +2 -8
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +2 -0
  6. data/README.md +37 -148
  7. data/lib/onfido.rb +3 -2
  8. data/lib/onfido/api.rb +18 -12
  9. data/lib/onfido/errors/connection_error.rb +2 -0
  10. data/lib/onfido/errors/onfido_error.rb +2 -0
  11. data/lib/onfido/errors/request_error.rb +2 -0
  12. data/lib/onfido/errors/server_error.rb +2 -0
  13. data/lib/onfido/options.rb +38 -0
  14. data/lib/onfido/resource.rb +45 -59
  15. data/lib/onfido/resources/address.rb +2 -0
  16. data/lib/onfido/resources/applicant.rb +2 -0
  17. data/lib/onfido/resources/check.rb +6 -0
  18. data/lib/onfido/resources/document.rb +2 -0
  19. data/lib/onfido/resources/extraction.rb +2 -0
  20. data/lib/onfido/resources/live_photo.rb +2 -0
  21. data/lib/onfido/resources/live_video.rb +2 -0
  22. data/lib/onfido/resources/report.rb +2 -0
  23. data/lib/onfido/resources/sdk_token.rb +2 -0
  24. data/lib/onfido/resources/webhook.rb +4 -2
  25. data/lib/onfido/version.rb +3 -1
  26. data/onfido.gemspec +5 -6
  27. data/spec/integrations/address_spec.rb +4 -2
  28. data/spec/integrations/applicant_spec.rb +12 -7
  29. data/spec/integrations/check_spec.rb +17 -4
  30. data/spec/integrations/document_spec.rb +7 -3
  31. data/spec/integrations/extraction_spec.rb +6 -2
  32. data/spec/integrations/live_photo_spec.rb +7 -3
  33. data/spec/integrations/live_video_spec.rb +6 -1
  34. data/spec/integrations/report_spec.rb +6 -1
  35. data/spec/integrations/resource_spec.rb +93 -0
  36. data/spec/integrations/sdk_token_spec.rb +5 -1
  37. data/spec/integrations/webhook_spec.rb +28 -24
  38. data/spec/onfido/api_spec.rb +14 -25
  39. data/spec/onfido/connection_error_spec.rb +4 -2
  40. data/spec/onfido/options_spec.rb +39 -0
  41. data/spec/onfido/request_error_spec.rb +4 -2
  42. data/spec/spec_helper.rb +3 -5
  43. data/spec/support/fake_onfido_api.rb +63 -49
  44. data/spec/support/fixtures/applicant.json +1 -1
  45. data/spec/support/fixtures/check.json +1 -1
  46. data/spec/support/fixtures/checks.json +1 -1
  47. data/spec/support/fixtures/document.json +1 -1
  48. data/spec/support/fixtures/documents.json +2 -2
  49. data/spec/support/fixtures/live_photo.json +2 -2
  50. data/spec/support/fixtures/live_photos.json +4 -4
  51. data/spec/support/fixtures/live_video.json +2 -2
  52. data/spec/support/fixtures/live_videos.json +2 -2
  53. data/spec/support/fixtures/report.json +1 -1
  54. data/spec/support/fixtures/reports.json +2 -2
  55. data/spec/support/fixtures/webhook.json +1 -1
  56. data/spec/support/fixtures/webhooks.json +2 -2
  57. metadata +11 -29
  58. data/Rakefile +0 -1
  59. data/lib/onfido/configuration.rb +0 -47
  60. data/lib/onfido/null_logger.rb +0 -5
  61. data/spec/integrations/exceptions_spec.rb +0 -72
  62. data/spec/onfido/resource_spec.rb +0 -133
  63. data/spec/onfido_spec.rb +0 -83
@@ -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.1/"
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,43 @@ 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. '
129
115
 
130
116
  when SocketError
131
- "Unexpected error when trying to connect to Onfido. " \
132
- "You may be seeing this message because your DNS is not working. " \
117
+ 'Unexpected error when trying to connect to Onfido. ' \
118
+ 'You may be seeing this message because your DNS is not working. ' \
133
119
  "To check, try running 'host onfido.com' from the command line."
134
120
 
135
121
  else
136
- "Unexpected error communicating with Onfido. " \
137
- "If this problem persists, let us know at info@onfido.com."
122
+ 'Unexpected error communicating with Onfido. ' \
123
+ 'If this problem persists, let us know at info@onfido.com.'
138
124
  end
139
125
 
140
126
  full_message = message + "\n\n(Network error: #{error.message})"
141
127
 
142
- raise ConnectionError.new(full_message)
128
+ raise ConnectionError, full_message
143
129
  end
144
130
 
145
131
  def validate_file!(file)
146
132
  return if file.respond_to?(:read) && file.respond_to?(:path)
147
133
 
148
- raise ArgumentError, "File must be a `File`-like object which responds to " \
149
- "`#read` and `#path`"
134
+ raise ArgumentError, 'File must be a `File`-like object which responds to ' \
135
+ '`#read` and `#path`'
150
136
  end
151
137
  end
152
138
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Onfido
2
4
  class Address < Resource
3
5
  def all(postcode)
@@ -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.1'.freeze
4
+ VERSION = '2.0.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
 
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  describe Onfido::Address do
2
- subject(:api) { Onfido::API.new }
4
+ include_context 'fake onfido api'
3
5
 
4
6
  describe '#all' do
5
7
  it 'returns the addresses matching the postcode' do
6
- response = api.address.all('SW1 4NG')
8
+ response = onfido.address.all('SW1 4NG')
7
9
 
8
10
  expect(response['addresses'].count).to eq(2)
9
11
  end
@@ -1,5 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  describe Onfido::Applicant do
2
- subject(:applicant) { described_class.new }
4
+ include_context 'fake onfido api'
5
+
6
+ subject(:applicant) { onfido.applicant }
7
+
3
8
  let(:applicant_id) { '61f659cb-c90b-4067-808a-6136b5c01351' }
4
9
  let(:params) do
5
10
  {
@@ -29,9 +34,9 @@ describe Onfido::Applicant do
29
34
 
30
35
  it 'serializes the payload correctly' do
31
36
  WebMock.after_request do |request_signature, _response|
32
- if request_signature.uri.path == 'v3/applicants'
33
- expect(Rack::Utils.parse_nested_query(request_signature.body)).
34
- to eq(params)
37
+ if request_signature.uri.path == 'v3.1/applicants'
38
+ expect(Rack::Utils.parse_nested_query(request_signature.body))
39
+ .to eq(params)
35
40
  end
36
41
  end
37
42
  end
@@ -93,13 +98,13 @@ describe Onfido::Applicant do
93
98
  it 'returns an error' do
94
99
  applicant_id = 'a2fb9c62-ab10-4898-a8ec-342c4b552ad5'
95
100
 
96
- expect { applicant.restore(applicant_id) }.to raise_error { |error|
101
+ expect { applicant.restore(applicant_id) }.to raise_error do |error|
97
102
  expect(error).to be_a(Onfido::RequestError)
98
103
  expect(error.message).to eq('There was a validation error on this request')
99
104
  expect(error.fields).to eq(
100
- "Applicant a2fb9c62-ab10-4898-a8ec-342c4b552ad5 is not scheduled for deletion"
105
+ 'Applicant a2fb9c62-ab10-4898-a8ec-342c4b552ad5 is not scheduled for deletion'
101
106
  )
102
- }
107
+ end
103
108
  end
104
109
  end
105
110
  end
@@ -1,5 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  describe Onfido::Check do
2
- subject(:check) { described_class.new }
4
+ include_context 'fake onfido api'
5
+
6
+ subject(:check) { onfido.check }
7
+
3
8
  let(:applicant_id) { '61f659cb-c90b-4067-808a-6136b5c01351' }
4
9
  let(:check_id) { '8546921-123123-123123' }
5
10
 
@@ -20,7 +25,7 @@ describe Onfido::Check do
20
25
  expect(response['id']).to eq(check_id)
21
26
  end
22
27
 
23
- it "returns report_ids" do
28
+ it 'returns report_ids' do
24
29
  response = check.find(check_id)
25
30
 
26
31
  expect(response['report_ids'].first).to be_a(String)
@@ -36,16 +41,24 @@ describe Onfido::Check do
36
41
  end
37
42
  end
38
43
 
39
- it "returns report_ids" do
44
+ it 'returns report_ids' do
40
45
  response = check.all(applicant_id)
41
46
 
42
47
  expect(response['checks'].first['report_ids'].first).to be_a(String)
43
48
  end
44
49
  end
45
50
 
46
- describe "#resume" do
51
+ describe '#resume' do
47
52
  it 'returns success response' do
48
53
  expect { check.resume(check_id) }.not_to raise_error
49
54
  end
50
55
  end
56
+
57
+ describe '#download' do
58
+ it 'returns the file data' do
59
+ response = check.download(check_id)
60
+
61
+ expect(response).not_to be_nil
62
+ end
63
+ end
51
64
  end