idnow 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +43 -0
- data/.travis.yml +4 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/Makefile +2 -0
- data/README.md +142 -0
- data/circle.yml +7 -0
- data/docs/IDnow_API.pdf +0 -0
- data/examples/idnow_automated_testing.rb +35 -0
- data/examples/idnow_download_identification.rb +16 -0
- data/examples/idnow_get_identification.rb +16 -0
- data/examples/idnow_upload_download_default_document.rb +33 -0
- data/idnow-client.gemspec +30 -0
- data/lib/idnow.rb +68 -0
- data/lib/idnow/API/authentication.rb +13 -0
- data/lib/idnow/API/automated_testing.rb +19 -0
- data/lib/idnow/API/document_definitions.rb +29 -0
- data/lib/idnow/API/download_documents.rb +13 -0
- data/lib/idnow/API/request_identifications.rb +12 -0
- data/lib/idnow/API/retrieve_identifications.rb +36 -0
- data/lib/idnow/API/upload_documents.rb +23 -0
- data/lib/idnow/client.rb +60 -0
- data/lib/idnow/configuration.rb +25 -0
- data/lib/idnow/exception.rb +25 -0
- data/lib/idnow/get_request.rb +10 -0
- data/lib/idnow/helpers.rb +9 -0
- data/lib/idnow/http_client.rb +27 -0
- data/lib/idnow/json_response.rb +11 -0
- data/lib/idnow/models/contact_data.rb +12 -0
- data/lib/idnow/models/document_definition.rb +15 -0
- data/lib/idnow/models/identification.rb +25 -0
- data/lib/idnow/models/identification_data.rb +60 -0
- data/lib/idnow/models/identification_document.rb +34 -0
- data/lib/idnow/models/identification_process.rb +29 -0
- data/lib/idnow/models/identification_request.rb +16 -0
- data/lib/idnow/models/login.rb +9 -0
- data/lib/idnow/models/login_data.rb +13 -0
- data/lib/idnow/models/user_data.rb +39 -0
- data/lib/idnow/modules/jsonable.rb +28 -0
- data/lib/idnow/post_binary_request.rb +11 -0
- data/lib/idnow/post_json_request.rb +12 -0
- data/lib/idnow/raw_response.rb +31 -0
- data/lib/idnow/sftp_client.rb +24 -0
- metadata +187 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
module Idnow
|
2
|
+
module API
|
3
|
+
module Authentication
|
4
|
+
def login
|
5
|
+
path = full_path_for('login')
|
6
|
+
login_data = Idnow::LoginData.new(@api_key)
|
7
|
+
request = Idnow::PostJsonRequest.new(path, login_data)
|
8
|
+
response = execute(request)
|
9
|
+
@auth_token = Idnow::Login.new(response.data).auth_token
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Idnow
|
2
|
+
module API
|
3
|
+
module AutomatedTesting
|
4
|
+
HOST = 'https://api.test.idnow.de'.freeze
|
5
|
+
|
6
|
+
def testing_start(transaction_number:)
|
7
|
+
path = full_path_for("identifications/#{transaction_number}/start")
|
8
|
+
request = Idnow::PostJsonRequest.new(path, {})
|
9
|
+
execute(request, 'X-API_KEY' => @api_key, http_client: automated_testing_http_client)
|
10
|
+
end
|
11
|
+
|
12
|
+
def testing_request_video_chat(transaction_number:)
|
13
|
+
path = full_path_for("identifications/#{transaction_number}/requestVideoChat")
|
14
|
+
request = Idnow::PostJsonRequest.new(path, {})
|
15
|
+
execute(request, 'X-API_KEY' => @api_key, http_client: automated_testing_http_client)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Idnow
|
2
|
+
module API
|
3
|
+
module DocumentDefinitions
|
4
|
+
def create_document_definition(document_data)
|
5
|
+
fail Idnow::AuthenticationException if @auth_token.nil?
|
6
|
+
|
7
|
+
path = full_path_for('documentdefinitions')
|
8
|
+
request = Idnow::PostJsonRequest.new(path, document_data)
|
9
|
+
execute(request, 'X-API-LOGIN-TOKEN' => @auth_token)
|
10
|
+
end
|
11
|
+
|
12
|
+
def list_document_definitions
|
13
|
+
fail Idnow::AuthenticationException if @auth_token.nil?
|
14
|
+
|
15
|
+
path = full_path_for('documentdefinitions')
|
16
|
+
request = Idnow::GetRequest.new(path)
|
17
|
+
response = execute(request, 'X-API-LOGIN-TOKEN' => @auth_token)
|
18
|
+
response.data.map do |data|
|
19
|
+
Idnow::DocumentDefinition.new(data)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def list_cached_document_definitions(refresh = false)
|
24
|
+
return @document_definitions = list_document_definitions if refresh
|
25
|
+
@document_definitions ||= list_document_definitions
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Idnow
|
2
|
+
module API
|
3
|
+
module DownloadDocuments
|
4
|
+
def download_default_document(document_definition_identifier)
|
5
|
+
fail Idnow::AuthenticationException if @auth_token.nil?
|
6
|
+
|
7
|
+
path = full_path_for("documentdefinitions/#{document_definition_identifier}/data")
|
8
|
+
request = Idnow::GetRequest.new(path, '')
|
9
|
+
execute(request, 'X-API-LOGIN-TOKEN' => @auth_token)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Idnow
|
2
|
+
module API
|
3
|
+
module RequestIdentifications
|
4
|
+
def request_identification(transaction_number:, identification_data:)
|
5
|
+
path = full_path_for("identifications/#{transaction_number}/start")
|
6
|
+
request = Idnow::PostJsonRequest.new(path, identification_data)
|
7
|
+
response = execute(request, 'X-API-KEY' => @api_key)
|
8
|
+
Idnow::IdentificationRequest.new(response.data, transaction_number, @target_host, @company_id)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Idnow
|
2
|
+
module API
|
3
|
+
module RetrieveIdentifications
|
4
|
+
IDENTIFICATION_STATUSES = %w(pending failed).freeze
|
5
|
+
|
6
|
+
def list_identifications(status: nil)
|
7
|
+
fail Idnow::AuthenticationException if @auth_token.nil?
|
8
|
+
|
9
|
+
unless status.nil? || IDENTIFICATION_STATUSES.include?(status)
|
10
|
+
fail Idnow::InvalidArguments, "Status #{status} not defined, possible options are: #{IDENTIFICATION_STATUSES.join(',')}"
|
11
|
+
end
|
12
|
+
partial_path = status.nil? ? 'identifications' : "identifications?#{status}=true"
|
13
|
+
path = full_path_for(partial_path)
|
14
|
+
request = Idnow::GetRequest.new(path)
|
15
|
+
response = execute(request, 'X-API-LOGIN-TOKEN' => @auth_token)
|
16
|
+
response.data['identifications'].map do |data|
|
17
|
+
Idnow::Identification.new(data)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_identification(transaction_number:)
|
22
|
+
fail Idnow::AuthenticationException if @auth_token.nil?
|
23
|
+
|
24
|
+
path = full_path_for("identifications/#{transaction_number}")
|
25
|
+
request = Idnow::GetRequest.new(path)
|
26
|
+
response = execute(request, 'X-API-LOGIN-TOKEN' => @auth_token)
|
27
|
+
Idnow::Identification.new(response.data)
|
28
|
+
end
|
29
|
+
|
30
|
+
def download_identification(transaction_number:)
|
31
|
+
path = "#{transaction_number}.zip"
|
32
|
+
@sftp_client.download(path)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Idnow
|
2
|
+
module API
|
3
|
+
module UploadDocuments
|
4
|
+
def upload_identification_document(transaction_number, document_definition_identifier, file_data)
|
5
|
+
request_path = full_path_for("identifications/#{transaction_number}/documents/#{document_definition_identifier}/data")
|
6
|
+
upload_document(file_data, request_path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def upload_default_document(document_definition_identifier, file_data)
|
10
|
+
request_path = full_path_for("documentdefinitions/#{document_definition_identifier}/data")
|
11
|
+
upload_document(file_data, request_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def upload_document(file_data, request_path)
|
17
|
+
fail Idnow::AuthenticationException if @auth_token.nil?
|
18
|
+
request = Idnow::PostBinaryRequest.new(request_path, file_data)
|
19
|
+
execute(request, 'X-API-LOGIN-TOKEN' => @auth_token)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/idnow/client.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'idnow/API/authentication'
|
2
|
+
require 'idnow/API/automated_testing' # shouldn't be included by default
|
3
|
+
require 'idnow/API/request_identifications'
|
4
|
+
require 'idnow/API/retrieve_identifications'
|
5
|
+
require 'idnow/API/document_definitions'
|
6
|
+
require 'idnow/API/upload_documents'
|
7
|
+
require 'idnow/API/download_documents'
|
8
|
+
|
9
|
+
module Idnow
|
10
|
+
class Client
|
11
|
+
include Idnow::API::Authentication
|
12
|
+
include Idnow::API::RetrieveIdentifications
|
13
|
+
include Idnow::API::RequestIdentifications
|
14
|
+
include Idnow::API::AutomatedTesting
|
15
|
+
include Idnow::API::DocumentDefinitions
|
16
|
+
include Idnow::API::UploadDocuments
|
17
|
+
include Idnow::API::DownloadDocuments
|
18
|
+
|
19
|
+
API_VERSION = 'v1'.freeze
|
20
|
+
|
21
|
+
attr_reader :host
|
22
|
+
|
23
|
+
def initialize(env:, company_id:, api_key:)
|
24
|
+
fail 'Please set env to :test or :live' unless Idnow::ENVIRONMENTS.keys.include?(env)
|
25
|
+
fail 'Please set your company_id' if company_id.nil?
|
26
|
+
fail 'Please set your api_key' if api_key.nil?
|
27
|
+
@host = Idnow::ENVIRONMENTS[env][:host]
|
28
|
+
@target_host = Idnow::ENVIRONMENTS[env][:target_host]
|
29
|
+
@company_id = company_id
|
30
|
+
@api_key = api_key
|
31
|
+
|
32
|
+
@http_client = HttpClient.new(host: @host)
|
33
|
+
@sftp_client = SftpClient.new(host: @host, username: @company_id, password: @api_key)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def execute(request, headers = {}, http_client: @http_client)
|
39
|
+
http_response = http_client.execute(request, headers)
|
40
|
+
|
41
|
+
response = if request.content_type == 'application/json'
|
42
|
+
Idnow::JsonResponse.new(http_response.body)
|
43
|
+
else
|
44
|
+
Idnow::RawResponse.new(http_response.body)
|
45
|
+
end
|
46
|
+
|
47
|
+
response.tap do |r|
|
48
|
+
fail Idnow::ResponseException, r.errors if r.errors?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def full_path_for(partial_path)
|
53
|
+
File.join('/api', API_VERSION, @company_id, partial_path)
|
54
|
+
end
|
55
|
+
|
56
|
+
def automated_testing_http_client
|
57
|
+
@automated_testing_http_client ||= HttpClient.new(host: Idnow::API::AutomatedTesting::HOST)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Idnow
|
2
|
+
class Configuration
|
3
|
+
# TODO: This class is not being used right now, but its aim is to be able for the developers
|
4
|
+
# using the gem to set its configuration with something like
|
5
|
+
# Idnow.config do |config|
|
6
|
+
# config.url = Idnow::TEST_SERVER
|
7
|
+
# config.env = :test
|
8
|
+
# config.company_id = company_id
|
9
|
+
# end
|
10
|
+
|
11
|
+
attr_accessor :api_key
|
12
|
+
|
13
|
+
attr_accessor :company_id
|
14
|
+
|
15
|
+
module Idnow
|
16
|
+
module Host
|
17
|
+
TEST = 'https://gateway.test.idnow.de'.freeze
|
18
|
+
PRODUCTION = 'https://gateway.idnow.de'.freeze
|
19
|
+
end
|
20
|
+
end
|
21
|
+
attr_accessor :host
|
22
|
+
|
23
|
+
attr_accessor :api_version
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Idnow
|
2
|
+
class Exception < StandardError
|
3
|
+
def initialize(message)
|
4
|
+
super("Request to IDnow failed: #{message}")
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class ConnectionException < Idnow::Exception
|
9
|
+
def initialize(exception)
|
10
|
+
super("#{exception.class}, #{exception.message}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ResponseException < Idnow::Exception
|
15
|
+
end
|
16
|
+
|
17
|
+
class AuthenticationException < Idnow::Exception
|
18
|
+
def initialize
|
19
|
+
super('Not authenticaton token found, please log in first')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class InvalidArguments < Idnow::Exception
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Idnow
|
2
|
+
class HttpClient
|
3
|
+
def initialize(host:)
|
4
|
+
@uri = URI.parse(host)
|
5
|
+
end
|
6
|
+
|
7
|
+
def execute(request, headers = {})
|
8
|
+
headers.each do |k, v|
|
9
|
+
request[k] = v
|
10
|
+
end
|
11
|
+
begin
|
12
|
+
client.request(request)
|
13
|
+
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
|
14
|
+
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
|
15
|
+
raise Idnow::ConnectionException, e
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def client
|
22
|
+
Net::HTTP.new(@uri.host, @uri.port).tap do |http|
|
23
|
+
http.use_ssl = true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Idnow
|
2
|
+
class DocumentDefinition
|
3
|
+
include Idnow::Jsonable
|
4
|
+
|
5
|
+
attr_accessor :optional, :name, :identifier, :mime_type, :sort_order
|
6
|
+
|
7
|
+
def initialize(data)
|
8
|
+
@optional = data['optional']
|
9
|
+
@name = data['name']
|
10
|
+
@identifier = data['identifier']
|
11
|
+
@mime_type = data['mimeType']
|
12
|
+
@sort_order = data['sortOrder']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'pry'
|
3
|
+
module Idnow
|
4
|
+
class Identification
|
5
|
+
extend Forwardable
|
6
|
+
include Idnow::Jsonable
|
7
|
+
|
8
|
+
attr_accessor :identification_process, :contact_data, :user_data,
|
9
|
+
:identification_document, :attachments, :esigning
|
10
|
+
|
11
|
+
def initialize(data)
|
12
|
+
@identification_process = IdentificationProcess.new(data['identificationprocess'])
|
13
|
+
@contact_data = ContactData.new(data['contactdata'])
|
14
|
+
@user_data = UserData.new(data['userdata'])
|
15
|
+
@identification_document = IdentificationDocument.new(data.fetch('identificationdocument', {}))
|
16
|
+
@attachments = data['attachments']
|
17
|
+
@esigning = data['esigning']
|
18
|
+
end
|
19
|
+
|
20
|
+
def esigning?
|
21
|
+
!@esigning.nil?
|
22
|
+
end
|
23
|
+
def_delegators :identification_process, :successful?, :result, :reason, :id, :transaction_number, :review_pending?
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Idnow
|
4
|
+
class IdentificationData
|
5
|
+
module Gender
|
6
|
+
MALE = 'MALE'.freeze
|
7
|
+
FEMALE = 'FEMALE'.freeze
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :birthplace, :birthname, :city, :country, :custom1,
|
11
|
+
:custom2, :custom3, :custom4, :custom5, :trackingid, :email, :firstname, :gender,
|
12
|
+
:lastname, :mobilephone, :nationality, :street, :streetnumber, :title, :zipcode
|
13
|
+
|
14
|
+
def initialize(params = {})
|
15
|
+
params.keys.each do |key|
|
16
|
+
fail ArgumentError, "Attribute #{key} is not supported!" unless respond_to?(key.to_sym)
|
17
|
+
|
18
|
+
send("#{key}=", params[key])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_json
|
23
|
+
result = {}
|
24
|
+
instance_variables.each do |attribute|
|
25
|
+
result[attribute.to_s.delete('@')] = instance_variable_get(attribute)
|
26
|
+
end
|
27
|
+
result.to_json
|
28
|
+
end
|
29
|
+
|
30
|
+
########### Getter / Setter ############
|
31
|
+
|
32
|
+
def birthday
|
33
|
+
@birthday.strftime('%Y-%m-%d') if @birthday
|
34
|
+
end
|
35
|
+
|
36
|
+
def birthday=(birthday)
|
37
|
+
@birthday = if birthday.instance_of?(Date) || birthday.instance_of?(DateTime)
|
38
|
+
birthday
|
39
|
+
else
|
40
|
+
Date.parse(birthday)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def country=(country)
|
45
|
+
fail ArgumentError, 'Country must be ISO 3166 two letter country code' unless country.instance_of?(String) && country.size == 2
|
46
|
+
|
47
|
+
@country = country.upcase
|
48
|
+
end
|
49
|
+
|
50
|
+
def gender=(gender)
|
51
|
+
if %w(M MALE).include?(gender.to_s.strip.upcase)
|
52
|
+
@gender = Gender::MALE
|
53
|
+
elsif %w(F FEMALE).include?(gender.to_s.strip.upcase)
|
54
|
+
@gender = Gender::FEMALE
|
55
|
+
else
|
56
|
+
fail ArgumentError, 'Provide valid value for gender: MALE or FEMALE'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|