finicity 0.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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +69 -0
- data/Rakefile +10 -0
- data/finicity.gemspec +31 -0
- data/lib/finicity.rb +42 -0
- data/lib/finicity/client.rb +350 -0
- data/lib/finicity/configuration.rb +13 -0
- data/lib/finicity/errors.rb +62 -0
- data/lib/finicity/logger.rb +19 -0
- data/lib/finicity/railtie.rb +22 -0
- data/lib/finicity/v1.rb +29 -0
- data/lib/finicity/v1/request/activate_accounts.rb +73 -0
- data/lib/finicity/v1/request/activate_accounts_with_mfa.rb +88 -0
- data/lib/finicity/v1/request/add_customer.rb +54 -0
- data/lib/finicity/v1/request/delete_customer.rb +45 -0
- data/lib/finicity/v1/request/discover_accounts.rb +71 -0
- data/lib/finicity/v1/request/discover_accounts_with_mfa.rb +87 -0
- data/lib/finicity/v1/request/get_accounts.rb +50 -0
- data/lib/finicity/v1/request/get_customers.rb +43 -0
- data/lib/finicity/v1/request/get_customers_by_username.rb +52 -0
- data/lib/finicity/v1/request/get_institution.rb +45 -0
- data/lib/finicity/v1/request/get_institutions.rb +45 -0
- data/lib/finicity/v1/request/get_login_form.rb +47 -0
- data/lib/finicity/v1/request/get_transactions.rb +60 -0
- data/lib/finicity/v1/request/interactive_refresh_account.rb +51 -0
- data/lib/finicity/v1/request/interactive_refresh_account_with_mfa.rb +74 -0
- data/lib/finicity/v1/request/refresh_accounts.rb +47 -0
- data/lib/finicity/v1/response/accounts.rb +75 -0
- data/lib/finicity/v1/response/customers.rb +36 -0
- data/lib/finicity/v1/response/error.rb +13 -0
- data/lib/finicity/v1/response/institutions.rb +38 -0
- data/lib/finicity/v1/response/login_form.rb +29 -0
- data/lib/finicity/v1/response/mfa.rb +22 -0
- data/lib/finicity/v1/response/transactions.rb +28 -0
- data/lib/finicity/v2.rb +7 -0
- data/lib/finicity/v2/request/partner_authentication.rb +39 -0
- data/lib/finicity/v2/response/partner_authentication.rb +12 -0
- data/lib/finicity/version.rb +3 -0
- data/spec/finicity/client_spec.rb +527 -0
- data/spec/finicity/v1/request/activate_accounts_spec.rb +49 -0
- data/spec/finicity/v1/request/activate_accounts_with_mfa_spec.rb +64 -0
- data/spec/finicity/v1/request/add_customer_spec.rb +37 -0
- data/spec/finicity/v1/request/delete_customer_spec.rb +18 -0
- data/spec/finicity/v1/request/discover_accounts_spec.rb +42 -0
- data/spec/finicity/v1/request/discover_accounts_with_mfa_spec.rb +59 -0
- data/spec/finicity/v1/request/get_accounts_spec.rb +18 -0
- data/spec/finicity/v1/request/get_customers_by_username_spec.rb +18 -0
- data/spec/finicity/v1/request/get_customers_spec.rb +18 -0
- data/spec/finicity/v1/request/get_institution_spec.rb +18 -0
- data/spec/finicity/v1/request/get_institutions_spec.rb +18 -0
- data/spec/finicity/v1/request/get_login_form_spec.rb +18 -0
- data/spec/finicity/v1/request/get_transactions_spec.rb +19 -0
- data/spec/finicity/v1/request/interactive_refresh_account_spec.rb +19 -0
- data/spec/finicity/v1/request/interactive_refresh_account_with_mfa_spec.rb +38 -0
- data/spec/finicity/v1/request/refresh_accounts_spec.rb +18 -0
- data/spec/finicity/v1/response/accounts_spec.rb +39 -0
- data/spec/finicity/v1/response/customers_spec.rb +19 -0
- data/spec/finicity/v1/response/error_spec.rb +19 -0
- data/spec/finicity/v1/response/institutions_spec.rb +19 -0
- data/spec/finicity/v1/response/login_form_spec.rb +31 -0
- data/spec/finicity/v1/response/mfa_spec.rb +23 -0
- data/spec/finicity/v1/response/transactions_spec.rb +47 -0
- data/spec/finicity/v2/request/partner_authentication_spec.rb +21 -0
- data/spec/finicity/v2/response/partner_authentication_spec.rb +15 -0
- data/spec/spec_helper.rb +36 -0
- metadata +265 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
module Finicity
|
2
|
+
class GenericError < ::StandardError
|
3
|
+
attr_reader :error_message, :http_status, :finicity_code
|
4
|
+
|
5
|
+
def initialize(error_message = nil, http_status = nil, finicity_code = nil)
|
6
|
+
@error_message = error_message
|
7
|
+
@http_status = http_status
|
8
|
+
@finicity_code = finicity_code
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
status = http_status.nil? ? "" : "[Status #{http_status}] "
|
13
|
+
code = finicity_code.nil? ? "" : "[Finicity Code #{finicity_code}] "
|
14
|
+
"#{status}#{code}#{error_message}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class AuthenticationError < ::Finicity::GenericError
|
19
|
+
end
|
20
|
+
|
21
|
+
class DuplicateCustomerError < ::StandardError
|
22
|
+
attr_reader :username
|
23
|
+
|
24
|
+
def initialize(username)
|
25
|
+
@username = username
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"Multiple customers found with username: #{username}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class FinicityAggregationError < ::StandardError
|
34
|
+
ERROR_CODE_MAP = {
|
35
|
+
'0' => 'Success.',
|
36
|
+
'102' => 'Retry error. Website is down or there is a connectivity issue.',
|
37
|
+
'103' => 'Invalid Credentials. Credentials must be updated.',
|
38
|
+
'106' => 'Account Name/Number/Type mismatch.',
|
39
|
+
'108' => 'End user action required at the third party site.',
|
40
|
+
'109' => 'Password change required at the third party site.',
|
41
|
+
'185' => 'MFA answer(s) missing.',
|
42
|
+
'187' => 'Incorrect answer to MFA challenge question.'
|
43
|
+
}
|
44
|
+
|
45
|
+
attr_reader :aggregation_status_code
|
46
|
+
|
47
|
+
def initialize(aggregation_status_code)
|
48
|
+
@aggregation_status_code = aggregation_status_code
|
49
|
+
end
|
50
|
+
|
51
|
+
def error_message
|
52
|
+
ERROR_CODE_MAP[aggregation_status_code.to_s] || 'Unknown Error'
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
"[Aggregation Status Code #{aggregation_status_code}] #{error_message}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class InvalidCredentialsError < ::Finicity::FinicityAggregationError
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Finicity
|
2
|
+
module Logger
|
3
|
+
def log_request
|
4
|
+
::Finicity.logger.debug do
|
5
|
+
log = "REQUEST: #{self.class.name}"
|
6
|
+
log << "\n URL: #{url}" if self.respond_to?(:url)
|
7
|
+
log << "\n QUERY: #{query}" if self.respond_to?(:query)
|
8
|
+
log << "\n BODY: #{mask_body(body)}" if self.respond_to?(:body)
|
9
|
+
log
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def mask_body(body)
|
14
|
+
body = body.gsub(/<value>.*<\/value>/, "<value>[FILTERED]</value>")
|
15
|
+
body = body.gsub(/<answer>.*<\/answer>/, "<answer>[FILTERED]</answer>")
|
16
|
+
body
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Finicity
|
2
|
+
class Railtie < ::Rails::Railtie
|
3
|
+
|
4
|
+
config.finicity = ::Finicity.config
|
5
|
+
|
6
|
+
initializer "finicity_configuration" do |app|
|
7
|
+
if File.exists?(::Rails.root.join('config', 'finicity.yml'))
|
8
|
+
|
9
|
+
yaml_file = ::YAML.load_file(::Rails.root.join('config', 'finicity.yml'))
|
10
|
+
|
11
|
+
::Finicity.configure do |config|
|
12
|
+
config.base_url = yaml_file['base_url']
|
13
|
+
config.partner_id = yaml_file['partner_id']
|
14
|
+
config.partner_secret = yaml_file['partner_secret']
|
15
|
+
config.app_key = yaml_file['app_key']
|
16
|
+
end
|
17
|
+
else
|
18
|
+
::Rails.logger.warn("Failed to load finicity.yml")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/finicity/v1.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'finicity/v1/request/activate_accounts'
|
2
|
+
require 'finicity/v1/request/activate_accounts_with_mfa'
|
3
|
+
require 'finicity/v1/request/add_customer'
|
4
|
+
require 'finicity/v1/request/delete_customer'
|
5
|
+
require 'finicity/v1/request/discover_accounts'
|
6
|
+
require 'finicity/v1/request/discover_accounts_with_mfa'
|
7
|
+
require 'finicity/v1/request/get_accounts'
|
8
|
+
require 'finicity/v1/request/get_customers_by_username'
|
9
|
+
require 'finicity/v1/request/get_customers'
|
10
|
+
require 'finicity/v1/request/get_institution'
|
11
|
+
require 'finicity/v1/request/get_institutions'
|
12
|
+
require 'finicity/v1/request/get_login_form'
|
13
|
+
require 'finicity/v1/request/get_transactions'
|
14
|
+
require 'finicity/v1/request/interactive_refresh_account'
|
15
|
+
require 'finicity/v1/request/interactive_refresh_account_with_mfa'
|
16
|
+
require 'finicity/v1/request/refresh_accounts'
|
17
|
+
|
18
|
+
require 'finicity/v1/response/accounts'
|
19
|
+
require 'finicity/v1/response/customers'
|
20
|
+
require 'finicity/v1/response/error'
|
21
|
+
require 'finicity/v1/response/institutions'
|
22
|
+
require 'finicity/v1/response/login_form'
|
23
|
+
require 'finicity/v1/response/mfa'
|
24
|
+
require 'finicity/v1/response/transactions'
|
25
|
+
|
26
|
+
module Finicity
|
27
|
+
module V1
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Finicity::V1
|
2
|
+
module Request
|
3
|
+
class ActivateAccounts
|
4
|
+
include ::Finicity::Logger
|
5
|
+
extend ::HTTPClient::IncludeClient
|
6
|
+
include_http_client do |client|
|
7
|
+
client.cookie_manager = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Attributes
|
12
|
+
#
|
13
|
+
attr_accessor :accounts,
|
14
|
+
:customer_id,
|
15
|
+
:institution_id,
|
16
|
+
:token
|
17
|
+
|
18
|
+
##
|
19
|
+
# Instance Methods
|
20
|
+
#
|
21
|
+
def initialize(token, customer_id, institution_id, accounts)
|
22
|
+
@accounts = accounts
|
23
|
+
@customer_id = customer_id
|
24
|
+
@institution_id = institution_id
|
25
|
+
@token = token
|
26
|
+
end
|
27
|
+
|
28
|
+
# The accounts parameter is the finicity representation of accounts
|
29
|
+
def activate_accounts
|
30
|
+
http_client.put(url, body, headers)
|
31
|
+
end
|
32
|
+
|
33
|
+
# The accounts parameter is the finicity representation of accounts
|
34
|
+
def body
|
35
|
+
builder = ::Nokogiri::XML::Builder.new do |xml|
|
36
|
+
xml.accounts {
|
37
|
+
accounts.each do |account|
|
38
|
+
xml.account {
|
39
|
+
xml.id(account.id)
|
40
|
+
xml.number(account.number)
|
41
|
+
xml.name(account.name)
|
42
|
+
xml.type(account.type)
|
43
|
+
}
|
44
|
+
end
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
builder.to_xml
|
49
|
+
end
|
50
|
+
|
51
|
+
def headers
|
52
|
+
{
|
53
|
+
'Finicity-App-Key' => ::Finicity.config.app_key,
|
54
|
+
'Finicity-App-Token' => token,
|
55
|
+
'Content-Type' => 'application/xml'
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def url
|
60
|
+
::URI.join(
|
61
|
+
::Finicity.config.base_url,
|
62
|
+
'v1/',
|
63
|
+
'customers/',
|
64
|
+
"#{customer_id}/",
|
65
|
+
'institutions/',
|
66
|
+
"#{institution_id}/",
|
67
|
+
'accounts'
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Finicity::V1
|
2
|
+
module Request
|
3
|
+
class ActivateAccountsWithMfa
|
4
|
+
include ::Finicity::Logger
|
5
|
+
extend ::HTTPClient::IncludeClient
|
6
|
+
include_http_client do |client|
|
7
|
+
client.cookie_manager = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Attributes
|
12
|
+
#
|
13
|
+
attr_accessor :accounts,
|
14
|
+
:customer_id,
|
15
|
+
:institution_id,
|
16
|
+
:mfa_credentials,
|
17
|
+
:mfa_session,
|
18
|
+
:token
|
19
|
+
|
20
|
+
##
|
21
|
+
# Instance Methods
|
22
|
+
#
|
23
|
+
def initialize(token, mfa_session, customer_id, institution_id, accounts, mfa_credentials)
|
24
|
+
@accounts = accounts
|
25
|
+
@customer_id = customer_id
|
26
|
+
@institution_id = institution_id
|
27
|
+
@mfa_credentials = mfa_credentials
|
28
|
+
@mfa_session = mfa_session
|
29
|
+
@token = token
|
30
|
+
end
|
31
|
+
|
32
|
+
def activate_accounts_with_mfa
|
33
|
+
http_client.put(url, body, headers)
|
34
|
+
end
|
35
|
+
|
36
|
+
# The accounts parameter is the finicity representation of accounts
|
37
|
+
def body
|
38
|
+
builder = ::Nokogiri::XML::Builder.new do |xml|
|
39
|
+
xml.accounts {
|
40
|
+
accounts.each do |account|
|
41
|
+
xml.account {
|
42
|
+
xml.id(account.id)
|
43
|
+
xml.number(account.number)
|
44
|
+
xml.name(account.name)
|
45
|
+
xml.type(account.type)
|
46
|
+
}
|
47
|
+
end
|
48
|
+
xml.mfaChallenges {
|
49
|
+
xml.questions {
|
50
|
+
mfa_credentials.each do |mfa_credential|
|
51
|
+
xml.question {
|
52
|
+
xml.text_(mfa_credential[:text])
|
53
|
+
xml.answer(mfa_credential[:answer])
|
54
|
+
}
|
55
|
+
end
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
builder.to_xml
|
62
|
+
end
|
63
|
+
|
64
|
+
def headers
|
65
|
+
{
|
66
|
+
'Finicity-App-Key' => ::Finicity.config.app_key,
|
67
|
+
'Finicity-App-Token' => token,
|
68
|
+
'Content-Type' => 'application/xml',
|
69
|
+
'MFA-Session' => mfa_session,
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def url
|
74
|
+
::URI.join(
|
75
|
+
::Finicity.config.base_url,
|
76
|
+
'v1/',
|
77
|
+
'customers/',
|
78
|
+
"#{customer_id}/",
|
79
|
+
'institutions/',
|
80
|
+
"#{institution_id}/",
|
81
|
+
'accounts/',
|
82
|
+
'mfa'
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Finicity::V1
|
2
|
+
module Request
|
3
|
+
class AddCustomer
|
4
|
+
include ::Finicity::Logger
|
5
|
+
extend ::HTTPClient::IncludeClient
|
6
|
+
include_http_client do |client|
|
7
|
+
client.cookie_manager = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Attributes
|
12
|
+
#
|
13
|
+
attr_accessor :token,
|
14
|
+
:user_guid
|
15
|
+
|
16
|
+
##
|
17
|
+
# Instance Methods
|
18
|
+
#
|
19
|
+
def initialize(token, user_guid)
|
20
|
+
@token = token
|
21
|
+
@user_guid = user_guid
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_customer
|
25
|
+
http_client.post(url, body, headers)
|
26
|
+
end
|
27
|
+
|
28
|
+
def body
|
29
|
+
{
|
30
|
+
'username' => user_guid,
|
31
|
+
'email' => "#{user_guid}@mx.com",
|
32
|
+
'firstName' => user_guid,
|
33
|
+
'lastName' => user_guid
|
34
|
+
}.to_xml(:root => 'customer')
|
35
|
+
end
|
36
|
+
|
37
|
+
def headers
|
38
|
+
{
|
39
|
+
'Finicity-App-Key' => ::Finicity.config.app_key,
|
40
|
+
'Finicity-App-Token' => token,
|
41
|
+
'Content-Type' => 'application/xml'
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def url
|
46
|
+
::URI.join(
|
47
|
+
::Finicity.config.base_url,
|
48
|
+
'v1/',
|
49
|
+
'customers'
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Finicity::V1
|
2
|
+
module Request
|
3
|
+
class DeleteCustomer
|
4
|
+
include ::Finicity::Logger
|
5
|
+
extend ::HTTPClient::IncludeClient
|
6
|
+
include_http_client do |client|
|
7
|
+
client.cookie_manager = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Attributes
|
12
|
+
#
|
13
|
+
attr_accessor :token,
|
14
|
+
:customer_id
|
15
|
+
|
16
|
+
##
|
17
|
+
# Instance Methods
|
18
|
+
#
|
19
|
+
def initialize(token, customer_id)
|
20
|
+
@customer_id = customer_id
|
21
|
+
@token = token
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete_customer
|
25
|
+
http_client.delete(url, nil, headers)
|
26
|
+
end
|
27
|
+
|
28
|
+
def headers
|
29
|
+
{
|
30
|
+
'Finicity-App-Key' => ::Finicity.config.app_key,
|
31
|
+
'Finicity-App-Token' => token
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def url
|
36
|
+
::URI.join(
|
37
|
+
::Finicity.config.base_url,
|
38
|
+
'v1/',
|
39
|
+
'customers/',
|
40
|
+
customer_id.to_s
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Finicity::V1
|
2
|
+
module Request
|
3
|
+
class DiscoverAccounts
|
4
|
+
include ::Finicity::Logger
|
5
|
+
extend ::HTTPClient::IncludeClient
|
6
|
+
include_http_client do |client|
|
7
|
+
client.cookie_manager = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Attributes
|
12
|
+
#
|
13
|
+
attr_accessor :customer_id,
|
14
|
+
:institution_id,
|
15
|
+
:login_credentials,
|
16
|
+
:token
|
17
|
+
|
18
|
+
##
|
19
|
+
# Instance Methods
|
20
|
+
#
|
21
|
+
def initialize(token, customer_id, institution_id, login_credentials)
|
22
|
+
@customer_id = customer_id
|
23
|
+
@institution_id = institution_id
|
24
|
+
@login_credentials = login_credentials
|
25
|
+
@token = token
|
26
|
+
end
|
27
|
+
|
28
|
+
def discover_accounts
|
29
|
+
http_client.post(url, body, headers)
|
30
|
+
end
|
31
|
+
|
32
|
+
def body
|
33
|
+
builder = ::Nokogiri::XML::Builder.new do |xml|
|
34
|
+
xml.accounts {
|
35
|
+
xml.credentials {
|
36
|
+
login_credentials.each do |login_credential|
|
37
|
+
xml.loginField {
|
38
|
+
xml.id(login_credential[:id])
|
39
|
+
xml.name(login_credential[:name])
|
40
|
+
xml.value(login_credential[:value])
|
41
|
+
}
|
42
|
+
end
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
builder.to_xml
|
48
|
+
end
|
49
|
+
|
50
|
+
def headers
|
51
|
+
{
|
52
|
+
'Finicity-App-Key' => ::Finicity.config.app_key,
|
53
|
+
'Finicity-App-Token' => token,
|
54
|
+
'Content-Type' => 'application/xml'
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def url
|
59
|
+
::URI.join(
|
60
|
+
::Finicity.config.base_url,
|
61
|
+
'v1/',
|
62
|
+
'customers/',
|
63
|
+
"#{customer_id}/",
|
64
|
+
'institutions/',
|
65
|
+
"#{institution_id}/",
|
66
|
+
'accounts'
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|