onfido 1.1.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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