ibanity 1.1 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +29 -0
- data/README.md +2 -0
- data/ibanity.gemspec +1 -2
- data/lib/ibanity.rb +8 -0
- data/lib/ibanity/api/base_resource.rb +4 -2
- data/lib/ibanity/api/o_auth_resource.rb +6 -0
- data/lib/ibanity/api/ponto_connect/account.rb +5 -0
- data/lib/ibanity/api/ponto_connect/financial_institution.rb +1 -1
- data/lib/ibanity/api/ponto_connect/integration.rb +10 -0
- data/lib/ibanity/api/ponto_connect/sandbox/financial_institution_account.rb +21 -0
- data/lib/ibanity/api/ponto_connect/sandbox/financial_institution_transaction.rb +31 -0
- data/lib/ibanity/api/ponto_connect/token.rb +27 -10
- data/lib/ibanity/api/ponto_connect/usage.rb +10 -0
- data/lib/ibanity/api/ponto_connect/user_info.rb +10 -0
- data/lib/ibanity/api/xs2a/bulk_payment_initiation_request.rb +33 -0
- data/lib/ibanity/api/xs2a/financial_institution_country.rb +10 -0
- data/lib/ibanity/api/xs2a/periodic_payment_initiation_request.rb +33 -0
- data/lib/ibanity/client.rb +2 -1
- data/lib/ibanity/collection.rb +10 -0
- data/lib/ibanity/error.rb +7 -4
- data/lib/ibanity/http_signature.rb +24 -19
- data/lib/ibanity/util.rb +11 -4
- data/lib/ibanity/version.rb +1 -1
- data/spec/lib/ibanity/http_signature_spec.rb +39 -0
- data/spec/lib/ibanity/util_spec.rb +89 -0
- data/spec/spec_helper.rb +102 -0
- data/spec/support/crypto_helper.rb +21 -0
- data/spec/support/fixtures/signature/test-certificate.pem +21 -0
- data/spec/support/fixtures/signature/test-private_key.pem +28 -0
- data/spec/support/fixtures/signature/test-public_key.pem +9 -0
- metadata +31 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 210db871fa1e9b4953293fd68cb50e781e83bfd6b24b6a3ef45329f45b3e1951
|
4
|
+
data.tar.gz: 90a0e99571a842e2634654f23ffe477a5b0f28e7a0af8ef93524afd27f00f40d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7e221288a48eeddfb8b3facaa4e8f4320244cb8b06f579af646fca4b5c44c439a45a5170a8f7914924c4453b0f52b52b3fef2ac44fde1ba7cb64a1fbaa10214
|
7
|
+
data.tar.gz: 73d19152ca69929356a0baf99b6bf2ce780aa392a2ad489997bf0ec3ba11a90b021bdf4347daff51f2f61e259ea53e8bbaa1f0d4bf8856ed016e259a91439d5d
|
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/.travis.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
language: ruby
|
2
|
+
script: bundle exec rspec
|
3
|
+
deploy:
|
4
|
+
provider: rubygems
|
5
|
+
api_key:
|
6
|
+
secure: pfXgGXH/AZEG3HMiaJPmJ7fck6Z3Hj0y7TU5TwvLAtKuBy6hlLT67ne/VfeBZQKa9d7eerr9PFP1hvLjZppScZMMOTtjBTvwpchkcUDwCxHx5GzS/jRnBF+uYHIza2p4Wq8yIPug7UrZ0qyq5VOG45R/nC/fPm2Ht2T7heqF5VgRaDGrN7Fq3zXn7duiYhTy02nDXorZ/kEAjnwdwDtXWyVFq8wr4inTExYrDP9/M57qx5TrkgWmcQ7JrvO2KfLDMJqAxI8lNoaPl5dAi7q1XWqqSVay7h9OAnP4UfvnvAc106lG6nHfTQig1krTfxRAvtHlPQjSlFkL+0qfBPBz1C/ex221O3NsNBYmI/mJ45lcNhqJbnkV2VEAEgUoe4ZFfKUUczLfnVxIPjoQmHMwLwfEO4g8/Hz/I3L7bvebgfzGGMDpmN6ERZRJmhutE6K5cL80ghoLs6ExJLoqHi1qvdBSkM2IyE4Yo+lob/hKU1IBL1w13T2h3EHapBh3kKn+jBzu/y5nXTEteBHbMP8j2zxFiihVBJEKPXhg/iU8WHLI6HZgWJkOc9ZH3hS7CN3VELK7fVZp9jaPAKaKihdvxQ0z3gCPFL+E6rYKsBPYqXE6qDsSQswhqTN15W0eVQqK8fDXkZmW0lSGvi2IJvL0CjIaahfB2GaapTtqOwar7sc=
|
7
|
+
on:
|
8
|
+
tags: true
|
9
|
+
gem: ibanity
|
10
|
+
skip_cleanup: true
|
11
|
+
notifications:
|
12
|
+
email: false
|
13
|
+
slack:
|
14
|
+
- rooms:
|
15
|
+
- secure: J06CK+muuVTW1SS1GmhSw7ZVo0vEMFpNWU5B9Cz94h5BZI3rPSxZFSCQG8OTQ/lBIrzPTlQj5JGzYgHpS5QRHGa4s1A1tYrZUfjUUgaZ7SIfoY8AgHH6cKF+jtwYy2z+kOJekBtfNLqfzAx+48QrxdbmBnXTG+r7UXczw0TAB7BMKh8107q7kqgjKiAnpGlXzC6rLWUwdRF/1qvDtYFCjoZ0OpYMnUUK+0/bgwVHxjYRl64DrPD3jC2XoaCTRCMyLbfqb9ZUXKVf27ByAQ/Ikj+qODdSH10vwPARXlbbVhpPfjAax42zC1OwSABdE00iJW1+TuoI69znjWg1d8Ti97raihV98OXMyqHXPKxX/gZp+0MSuYIE9GQWY791ulmQ+GwwkgB6v2LmXGCE8K+eUCc3zkGJWVUzBP+Wu49mDzDAQHBPl/G3u26RqmVQzWhk9ckHQ30cyIPFjz/eaMrda+wgQ6AKzfNq+XVL6hAO+Se28PRPhDu33ZzIKqgpk0dH77LcKPI/Uf1dCT+0oa+pvVx1T0Z93SNp0azh71rx9AOWBMZm7TcOYvMOw9QpVBZkoWy4NQo9PMT0Jo73qAnOTHadr8b5zeDoAu7jnlhCxIpmnrmIh4Dz6n6XF+c+d+C/MAQVQ0rKj7KzTYEsYat0NQ62lgBtHy5/Qmu736MaIVA=
|
16
|
+
if: (tag =~ ^v) AND (branch = master)
|
17
|
+
- rooms:
|
18
|
+
- secure: J06CK+muuVTW1SS1GmhSw7ZVo0vEMFpNWU5B9Cz94h5BZI3rPSxZFSCQG8OTQ/lBIrzPTlQj5JGzYgHpS5QRHGa4s1A1tYrZUfjUUgaZ7SIfoY8AgHH6cKF+jtwYy2z+kOJekBtfNLqfzAx+48QrxdbmBnXTG+r7UXczw0TAB7BMKh8107q7kqgjKiAnpGlXzC6rLWUwdRF/1qvDtYFCjoZ0OpYMnUUK+0/bgwVHxjYRl64DrPD3jC2XoaCTRCMyLbfqb9ZUXKVf27ByAQ/Ikj+qODdSH10vwPARXlbbVhpPfjAax42zC1OwSABdE00iJW1+TuoI69znjWg1d8Ti97raihV98OXMyqHXPKxX/gZp+0MSuYIE9GQWY791ulmQ+GwwkgB6v2LmXGCE8K+eUCc3zkGJWVUzBP+Wu49mDzDAQHBPl/G3u26RqmVQzWhk9ckHQ30cyIPFjz/eaMrda+wgQ6AKzfNq+XVL6hAO+Se28PRPhDu33ZzIKqgpk0dH77LcKPI/Uf1dCT+0oa+pvVx1T0Z93SNp0azh71rx9AOWBMZm7TcOYvMOw9QpVBZkoWy4NQo9PMT0Jo73qAnOTHadr8b5zeDoAu7jnlhCxIpmnrmIh4Dz6n6XF+c+d+C/MAQVQ0rKj7KzTYEsYat0NQ62lgBtHy5/Qmu736MaIVA=
|
19
|
+
on_success: change
|
20
|
+
on_failure: always
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## 1.5
|
4
|
+
|
5
|
+
* Proper release of previous enhancements
|
6
|
+
|
7
|
+
## 1.4
|
8
|
+
|
9
|
+
*Don't use this version as it was not properly released !*
|
10
|
+
|
11
|
+
## 1.3
|
12
|
+
|
13
|
+
### Enhancements
|
14
|
+
|
15
|
+
* [Ponto Connect] Add support for the /userinfo and /organizations/{id}/usage endpoints.
|
16
|
+
|
17
|
+
## 1.2
|
18
|
+
|
19
|
+
### Enhancements
|
20
|
+
|
21
|
+
* Default signature algorithm is now ["hs2019"](https://tools.ietf.org/html/draft-cavage-http-signatures-12#appendix-E.2)
|
22
|
+
* Add support for periodic and bulk payments
|
23
|
+
* Add snake-case transformation for deeply nested data structures
|
24
|
+
|
25
|
+
## 1.1.1
|
26
|
+
|
27
|
+
### Enhancements
|
28
|
+
|
29
|
+
* Improve debugging by logging the `ibanity_request_id` header from the response in case of error
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/ibanity/ibanity-ruby.svg?branch=master)](https://travis-ci.org/ibanity/ibanity-ruby)
|
2
|
+
|
1
3
|
# Ibanity Ruby Library
|
2
4
|
|
3
5
|
The Ibanity Ruby Library provides convenient wrappers around the Ibanity API. The object attributes are dynamically defined based on the API response, supporting minor API changes seamlessly.
|
data/ibanity.gemspec
CHANGED
@@ -19,6 +19,5 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency "rest-client", ">= 1.8.0"
|
22
|
-
spec.add_development_dependency "rspec", "3.
|
23
|
-
spec.add_development_dependency "webmock", "1.24.2"
|
22
|
+
spec.add_development_dependency "rspec", "3.9.0"
|
24
23
|
end
|
data/lib/ibanity.rb
CHANGED
@@ -15,12 +15,15 @@ require_relative "ibanity/api/xs2a/account"
|
|
15
15
|
require_relative "ibanity/api/xs2a/transaction"
|
16
16
|
require_relative "ibanity/api/xs2a/holding"
|
17
17
|
require_relative "ibanity/api/xs2a/financial_institution"
|
18
|
+
require_relative "ibanity/api/xs2a/financial_institution_country"
|
18
19
|
require_relative "ibanity/api/xs2a/account_information_access_request"
|
19
20
|
require_relative "ibanity/api/xs2a/account_information_access_request_authorization"
|
20
21
|
require_relative "ibanity/api/xs2a/payment_initiation_request_authorization"
|
21
22
|
require_relative "ibanity/api/xs2a/customer_access_token"
|
22
23
|
require_relative "ibanity/api/xs2a/customer"
|
23
24
|
require_relative "ibanity/api/xs2a/payment_initiation_request"
|
25
|
+
require_relative "ibanity/api/xs2a/bulk_payment_initiation_request"
|
26
|
+
require_relative "ibanity/api/xs2a/periodic_payment_initiation_request"
|
24
27
|
require_relative "ibanity/api/xs2a/synchronization"
|
25
28
|
require_relative "ibanity/api/o_auth_resource"
|
26
29
|
require_relative "ibanity/api/isabel_connect/account"
|
@@ -43,6 +46,11 @@ require_relative "ibanity/api/ponto_connect/synchronization"
|
|
43
46
|
require_relative "ibanity/api/consent/consent"
|
44
47
|
require_relative "ibanity/api/consent/processing_operation"
|
45
48
|
require_relative "ibanity/api/ponto_connect/payment"
|
49
|
+
require_relative "ibanity/api/ponto_connect/user_info"
|
50
|
+
require_relative "ibanity/api/ponto_connect/usage"
|
51
|
+
require_relative "ibanity/api/ponto_connect/integration"
|
52
|
+
require_relative "ibanity/api/ponto_connect/sandbox/financial_institution_account"
|
53
|
+
require_relative "ibanity/api/ponto_connect/sandbox/financial_institution_transaction"
|
46
54
|
|
47
55
|
module Ibanity
|
48
56
|
class << self
|
@@ -92,18 +92,20 @@ module Ibanity
|
|
92
92
|
attributes = raw["attributes"] || {}
|
93
93
|
meta = raw["meta"] || {}
|
94
94
|
params = base.merge(attributes).merge(meta)
|
95
|
-
Ibanity::Util.
|
95
|
+
Ibanity::Util.underscorize(params)
|
96
96
|
end
|
97
97
|
|
98
98
|
def setup_relationships(relationships, customer_access_token = nil)
|
99
99
|
relationships.each do |key, relationship|
|
100
100
|
if relationship["data"]
|
101
|
+
self[Ibanity::Util.underscore("#{key}_id")] = relationship["data"]["id"]
|
102
|
+
return unless relationship.dig("links", "related")
|
103
|
+
|
101
104
|
klass = relationship_klass(key)
|
102
105
|
method_name = Ibanity::Util.underscore(key)
|
103
106
|
define_singleton_method(method_name) do |headers: nil|
|
104
107
|
klass.find_by_uri(uri: relationship["links"]["related"], headers: headers, customer_access_token: customer_access_token)
|
105
108
|
end
|
106
|
-
self[Ibanity::Util.underscore("#{key}_id")] = relationship["data"]["id"]
|
107
109
|
else
|
108
110
|
singular_key = key[0..-2]
|
109
111
|
klass = relationship_klass(singular_key)
|
@@ -6,6 +6,12 @@ module Ibanity
|
|
6
6
|
new(raw_item)
|
7
7
|
end
|
8
8
|
|
9
|
+
def self.find_by_uri(uri:, customer_access_token: nil, headers: nil)
|
10
|
+
raw_item = Ibanity.client.get(uri: uri, customer_access_token: customer_access_token, headers: headers)
|
11
|
+
raw_item = {} if raw_item == ""
|
12
|
+
new(raw_item)
|
13
|
+
end
|
14
|
+
|
9
15
|
def initialize(raw)
|
10
16
|
super(raw)
|
11
17
|
end
|
@@ -10,6 +10,11 @@ module Ibanity
|
|
10
10
|
uri = Ibanity.ponto_connect_api_schema["accounts"].sub("{accountId}", id)
|
11
11
|
find_by_uri(uri: uri, customer_access_token: access_token)
|
12
12
|
end
|
13
|
+
|
14
|
+
def self.delete(access_token:, id:)
|
15
|
+
uri = Ibanity.ponto_connect_api_schema["accounts"].sub("{accountId}", id)
|
16
|
+
destroy_by_uri(uri: uri, customer_access_token: access_token)
|
17
|
+
end
|
13
18
|
end
|
14
19
|
end
|
15
20
|
end
|
@@ -6,7 +6,7 @@ module Ibanity
|
|
6
6
|
list_by_uri(uri: uri, query_params: query_params, customer_access_token: access_token)
|
7
7
|
end
|
8
8
|
|
9
|
-
def self.find(access_token
|
9
|
+
def self.find(access_token: nil, id:)
|
10
10
|
uri = Ibanity.ponto_connect_api_schema["financialInstitutions"].sub("{financialInstitutionId}", id)
|
11
11
|
find_by_uri(uri: uri, customer_access_token: access_token)
|
12
12
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Ibanity
|
2
|
+
module PontoConnect
|
3
|
+
class Integration < Ibanity::BaseResource
|
4
|
+
def self.delete(client_access_token:, organization_id:)
|
5
|
+
uri = Ibanity.ponto_connect_api_schema["organizations"]["integration"].sub("{organizationId}", organization_id)
|
6
|
+
destroy_by_uri(uri: uri, customer_access_token: client_access_token)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Ibanity
|
2
|
+
module PontoConnect
|
3
|
+
module Sandbox
|
4
|
+
class FinancialInstitutionAccount < Ibanity::BaseResource
|
5
|
+
def self.list(access_token:, financial_institution_id:, **query_params)
|
6
|
+
uri = Ibanity.ponto_connect_api_schema["sandbox"]["financialInstitution"]["financialInstitutionAccounts"]
|
7
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
8
|
+
.gsub("{financialInstitutionAccountId}", "")
|
9
|
+
list_by_uri(uri: uri, query_params: query_params, customer_access_token: access_token)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.find(access_token:, id:, financial_institution_id:)
|
13
|
+
uri = Ibanity.ponto_connect_api_schema["sandbox"]["financialInstitution"]["financialInstitutionAccounts"]
|
14
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
15
|
+
.gsub("{financialInstitutionAccountId}", id)
|
16
|
+
find_by_uri(uri: uri, customer_access_token: access_token)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Ibanity
|
2
|
+
module PontoConnect
|
3
|
+
module Sandbox
|
4
|
+
class FinancialInstitutionTransaction < Ibanity::BaseResource
|
5
|
+
def self.list(access_token:, financial_institution_account_id:, financial_institution_id:, **query_params)
|
6
|
+
uri = Ibanity.ponto_connect_api_schema["sandbox"]["financialInstitution"]["financialInstitutionAccount"]["financialInstitutionTransactions"]
|
7
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
8
|
+
.gsub("{financialInstitutionAccountId}", financial_institution_account_id)
|
9
|
+
.gsub("{financialInstitutionTransactionId}", "")
|
10
|
+
list_by_uri(uri: uri, query_params: query_params, customer_access_token: access_token)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.find(access_token:, id:, financial_institution_id:, financial_institution_account_id:)
|
14
|
+
uri = Ibanity.ponto_connect_api_schema["sandbox"]["financialInstitution"]["financialInstitutionAccount"]["financialInstitutionTransactions"]
|
15
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
16
|
+
.gsub("{financialInstitutionAccountId}", financial_institution_account_id)
|
17
|
+
.gsub("{financialInstitutionTransactionId}", id)
|
18
|
+
find_by_uri(uri: uri, customer_access_token: access_token)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.create(access_token:, financial_institution_id:, financial_institution_account_id:, **attributes)
|
22
|
+
uri = Ibanity.ponto_connect_api_schema["sandbox"]["financialInstitution"]["financialInstitutionAccount"]["financialInstitutionTransactions"]
|
23
|
+
.sub("{financialInstitutionId}", financial_institution_id)
|
24
|
+
.sub("{financialInstitutionAccountId}", financial_institution_account_id)
|
25
|
+
.sub("{financialInstitutionTransactionId}", "")
|
26
|
+
create_by_uri(uri: uri, resource_type: "financialInstitutionTransaction", attributes: attributes, customer_access_token: access_token)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -2,16 +2,33 @@ module Ibanity
|
|
2
2
|
module PontoConnect
|
3
3
|
class Token < Ibanity::OAuthResource
|
4
4
|
def self.create(refresh_token: nil, authorization_code: nil, redirect_uri: nil, idempotency_key: nil, code_verifier: nil)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
arguments =
|
6
|
+
if refresh_token
|
7
|
+
[
|
8
|
+
["grant_type", "refresh_token"],
|
9
|
+
["client_id", Ibanity.client.ponto_connect_client_id],
|
10
|
+
["refresh_token", refresh_token]
|
11
|
+
]
|
12
|
+
elsif authorization_code
|
13
|
+
[
|
14
|
+
["grant_type", "authorization_code"],
|
15
|
+
["client_id", Ibanity.client.ponto_connect_client_id],
|
16
|
+
["code", authorization_code],
|
17
|
+
["code_verifier", code_verifier],
|
18
|
+
["redirect_uri", redirect_uri]
|
19
|
+
]
|
20
|
+
else
|
21
|
+
[
|
22
|
+
["grant_type", "client_credentials"]
|
23
|
+
]
|
24
|
+
end
|
25
|
+
|
26
|
+
create_by_uri(
|
27
|
+
uri: Ibanity.ponto_connect_api_schema["oauth2"]["token"],
|
28
|
+
payload: URI.encode_www_form(arguments),
|
29
|
+
idempotency_key: idempotency_key,
|
30
|
+
headers: self.headers
|
31
|
+
)
|
15
32
|
end
|
16
33
|
|
17
34
|
def self.delete(refresh_token:)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Ibanity
|
2
|
+
module PontoConnect
|
3
|
+
class Usage < Ibanity::BaseResource
|
4
|
+
def self.find(client_access_token:, organization_id:, month:)
|
5
|
+
uri = Ibanity.ponto_connect_api_schema["organizations"]["usage"].sub("{organizationId}", organization_id).sub("{month}", month)
|
6
|
+
find_by_uri(uri: uri, customer_access_token: client_access_token)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Ibanity
|
2
|
+
module Xs2a
|
3
|
+
class BulkPaymentInitiationRequest < Ibanity::BaseResource
|
4
|
+
def self.create_for_financial_institution(financial_institution_id:, customer_access_token:, idempotency_key: nil, **attributes)
|
5
|
+
path = Ibanity.xs2a_api_schema["customer"]["financialInstitution"]["bulkPaymentInitiationRequests"]
|
6
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
7
|
+
.sub("{paymentInitiationRequestId}", "")
|
8
|
+
uri = Ibanity.client.build_uri(path)
|
9
|
+
create_by_uri(
|
10
|
+
uri: uri,
|
11
|
+
resource_type: "bulkPaymentInitiationRequest",
|
12
|
+
attributes: attributes,
|
13
|
+
customer_access_token: customer_access_token,
|
14
|
+
idempotency_key: idempotency_key
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.find(id:, financial_institution_id:, customer_access_token:)
|
19
|
+
uri = Ibanity.xs2a_api_schema["customer"]["financialInstitution"]["bulkPaymentInitiationRequests"]
|
20
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
21
|
+
.sub("{paymentInitiationRequestId}", id)
|
22
|
+
find_by_uri(uri: uri, customer_access_token: customer_access_token)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.delete(id:, financial_institution_id:, customer_access_token:)
|
26
|
+
uri = Ibanity.xs2a_api_schema["customer"]["financialInstitution"]["bulkPaymentInitiationRequests"]
|
27
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
28
|
+
.sub("{paymentInitiationRequestId}", id)
|
29
|
+
destroy_by_uri(uri: uri, customer_access_token: customer_access_token)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Ibanity
|
2
|
+
module Xs2a
|
3
|
+
class FinancialInstitutionCountry < Ibanity::BaseResource
|
4
|
+
def self.list(**query_params)
|
5
|
+
uri = Ibanity.xs2a_api_schema["financialInstitutionCountries"]
|
6
|
+
list_by_uri(uri: uri, query_params: query_params)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Ibanity
|
2
|
+
module Xs2a
|
3
|
+
class PeriodicPaymentInitiationRequest < Ibanity::BaseResource
|
4
|
+
def self.create_for_financial_institution(financial_institution_id:, customer_access_token:, idempotency_key: nil, **attributes)
|
5
|
+
path = Ibanity.xs2a_api_schema["customer"]["financialInstitution"]["periodicPaymentInitiationRequests"]
|
6
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
7
|
+
.sub("{paymentInitiationRequestId}", "")
|
8
|
+
uri = Ibanity.client.build_uri(path)
|
9
|
+
create_by_uri(
|
10
|
+
uri: uri,
|
11
|
+
resource_type: "periodicPaymentInitiationRequest",
|
12
|
+
attributes: attributes,
|
13
|
+
customer_access_token: customer_access_token,
|
14
|
+
idempotency_key: idempotency_key
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.find(id:, financial_institution_id:, customer_access_token:)
|
19
|
+
uri = Ibanity.xs2a_api_schema["customer"]["financialInstitution"]["periodicPaymentInitiationRequests"]
|
20
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
21
|
+
.sub("{paymentInitiationRequestId}", id)
|
22
|
+
find_by_uri(uri: uri, customer_access_token: customer_access_token)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.delete(id:, financial_institution_id:, customer_access_token:)
|
26
|
+
uri = Ibanity.xs2a_api_schema["customer"]["financialInstitution"]["periodicPaymentInitiationRequests"]
|
27
|
+
.gsub("{financialInstitutionId}", financial_institution_id)
|
28
|
+
.sub("{paymentInitiationRequestId}", id)
|
29
|
+
destroy_by_uri(uri: uri, customer_access_token: customer_access_token)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/ibanity/client.rb
CHANGED
@@ -70,8 +70,9 @@ module Ibanity
|
|
70
70
|
}
|
71
71
|
raw_response = RestClient::Request.execute(query) do |response, request, result, &block|
|
72
72
|
if response.code >= 400
|
73
|
+
ibanity_request_id = response.headers[:ibanity_request_id]
|
73
74
|
body = JSON.parse(response.body)
|
74
|
-
raise Ibanity::Error.new(body["errors"] || body), "Ibanity request failed."
|
75
|
+
raise Ibanity::Error.new(body["errors"] || body, ibanity_request_id), "Ibanity request failed."
|
75
76
|
else
|
76
77
|
response.return!(&block)
|
77
78
|
end
|
data/lib/ibanity/collection.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Ibanity
|
2
2
|
class Collection < DelegateClass(Array)
|
3
3
|
attr_accessor :page_limit,
|
4
|
+
:page_number,
|
5
|
+
:page_size,
|
6
|
+
:total_entries,
|
7
|
+
:total_pages,
|
4
8
|
:before_cursor,
|
5
9
|
:after_cursor,
|
6
10
|
:offset,
|
@@ -8,6 +12,7 @@ module Ibanity
|
|
8
12
|
:first_link,
|
9
13
|
:next_link,
|
10
14
|
:previous_link,
|
15
|
+
:last_link,
|
11
16
|
:latest_synchronization,
|
12
17
|
:synchronized_at
|
13
18
|
|
@@ -23,6 +28,10 @@ module Ibanity
|
|
23
28
|
links ||= {}
|
24
29
|
@klass = klass
|
25
30
|
@page_limit = paging["limit"]
|
31
|
+
@page_number = paging["pageNumber"]
|
32
|
+
@page_size = paging["pageSize"]
|
33
|
+
@total_entries = paging["totalEntries"]
|
34
|
+
@total_pages = paging["totalPages"]
|
26
35
|
@before_cursor = paging["before"]
|
27
36
|
@after_cursor = paging["after"]
|
28
37
|
@offset = paging["offset"]
|
@@ -30,6 +39,7 @@ module Ibanity
|
|
30
39
|
@first_link = links["first"]
|
31
40
|
@next_link = links["next"]
|
32
41
|
@previous_link = links["prev"]
|
42
|
+
@last_link = links["last"]
|
33
43
|
@synchronized_at = synchronized_at
|
34
44
|
@latest_synchronization = latest_synchronization
|
35
45
|
super(items)
|
data/lib/ibanity/error.rb
CHANGED
@@ -2,13 +2,14 @@ module Ibanity
|
|
2
2
|
class Error < StandardError
|
3
3
|
attr_reader :errors
|
4
4
|
|
5
|
-
def initialize(errors)
|
5
|
+
def initialize(errors, ibanity_request_id)
|
6
6
|
@errors = errors
|
7
|
+
@ibanity_request_id = ibanity_request_id
|
7
8
|
end
|
8
9
|
|
9
10
|
def to_s
|
10
11
|
if @errors.is_a?(Array) && @errors.size > 0
|
11
|
-
@errors.map do |error|
|
12
|
+
formatted_errors = @errors.map do |error|
|
12
13
|
if error["meta"] && error["meta"]["attribute"]
|
13
14
|
"* #{error["code"]}: '#{error["meta"]["attribute"]}' #{error["detail"]}"
|
14
15
|
elsif error["meta"] && error["meta"]["resource"]
|
@@ -16,9 +17,11 @@ module Ibanity
|
|
16
17
|
else
|
17
18
|
"* #{error["code"]}: #{error["detail"]}"
|
18
19
|
end
|
19
|
-
end
|
20
|
+
end
|
21
|
+
formatted_errors << "* ibanity_request_id: #{@ibanity_request_id}"
|
22
|
+
formatted_errors.join("\n")
|
20
23
|
elsif @errors.is_a?(Hash)
|
21
|
-
"* #{@errors["error"]}: #{@errors["error_description"]}"
|
24
|
+
"* #{@errors["error"]}: #{@errors["error_description"]}\n * Error hint: #{@errors["error_hint"]}\n * ibanity_request_id: #{@ibanity_request_id}"
|
22
25
|
else
|
23
26
|
super
|
24
27
|
end
|
@@ -2,6 +2,9 @@ require "base64"
|
|
2
2
|
|
3
3
|
module Ibanity
|
4
4
|
class HttpSignature
|
5
|
+
PSS_DIGEST_ALGORITHM = "SHA256"
|
6
|
+
SIGNATURE_ALGORITHM = "hs2019"
|
7
|
+
|
5
8
|
def initialize(certificate:, certificate_id:, key:, method:, uri:, query_params:, headers:, payload:)
|
6
9
|
@certificate = certificate
|
7
10
|
@certificate_id = certificate_id
|
@@ -13,6 +16,21 @@ module Ibanity
|
|
13
16
|
@query_params = query_params
|
14
17
|
end
|
15
18
|
|
19
|
+
def signature_headers
|
20
|
+
{
|
21
|
+
"Digest" => payload_digest,
|
22
|
+
"Signature" => [
|
23
|
+
%(keyId="#{@certificate_id}"),
|
24
|
+
%(created="#{date}"),
|
25
|
+
%(algorithm="#{SIGNATURE_ALGORITHM}"),
|
26
|
+
%(headers="#{headers_to_sign.join(" ")}"),
|
27
|
+
%(signature="#{base64_signature}"),
|
28
|
+
].join(",")
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
16
34
|
def payload_digest
|
17
35
|
digest = OpenSSL::Digest::SHA512.new
|
18
36
|
string_payload = @payload.nil? ? "" : @payload
|
@@ -21,12 +39,8 @@ module Ibanity
|
|
21
39
|
"SHA-512=#{base64}"
|
22
40
|
end
|
23
41
|
|
24
|
-
def signature_algorithm
|
25
|
-
@certificate.signature_algorithm.match("sha256") ? "rsa-sha256" : "rsa-sha512"
|
26
|
-
end
|
27
|
-
|
28
42
|
def headers_to_sign
|
29
|
-
result = ["(request-target)", "host", "digest", "
|
43
|
+
result = ["(request-target)", "host", "digest", "(created)"]
|
30
44
|
result << "authorization" unless @headers["Authorization"].nil?
|
31
45
|
@headers.keys.each do |header|
|
32
46
|
result << header.to_s.downcase if header.to_s.match(/ibanity/i)
|
@@ -35,13 +49,12 @@ module Ibanity
|
|
35
49
|
end
|
36
50
|
|
37
51
|
def request_target
|
38
|
-
@uri.query =
|
52
|
+
@uri.query = RestClient::Utils.encode_query_string(@query_params) if @query_params&.keys&.any?
|
39
53
|
"#{@method} #{@uri.request_uri}"
|
40
54
|
end
|
41
55
|
|
42
56
|
def base64_signature
|
43
|
-
|
44
|
-
signature = @key.sign(digest, signing_string)
|
57
|
+
signature = @key.sign_pss(PSS_DIGEST_ALGORITHM, signing_string, salt_length: :digest, mgf1_hash: PSS_DIGEST_ALGORITHM)
|
45
58
|
Base64.urlsafe_encode64(signature)
|
46
59
|
end
|
47
60
|
|
@@ -50,13 +63,13 @@ module Ibanity
|
|
50
63
|
end
|
51
64
|
|
52
65
|
def date
|
53
|
-
@date ||= Time.now.
|
66
|
+
@date ||= Time.now.to_i
|
54
67
|
end
|
55
68
|
|
56
69
|
def signing_string
|
57
70
|
result = []
|
58
71
|
headers_to_sign.each do |header_to_sign|
|
59
|
-
value
|
72
|
+
value = header_value(header_to_sign)
|
60
73
|
result << "#{header_to_sign}: #{value}"
|
61
74
|
end
|
62
75
|
result.join("\n")
|
@@ -70,20 +83,12 @@ module Ibanity
|
|
70
83
|
host
|
71
84
|
when "digest"
|
72
85
|
payload_digest
|
73
|
-
when "
|
86
|
+
when "(created)"
|
74
87
|
date
|
75
88
|
else
|
76
89
|
camelized_header = header.split("-").collect(&:capitalize).join("-")
|
77
90
|
@headers[camelized_header]
|
78
91
|
end
|
79
92
|
end
|
80
|
-
|
81
|
-
def signature_headers
|
82
|
-
{
|
83
|
-
"Date" => date,
|
84
|
-
"Digest" => payload_digest,
|
85
|
-
"Signature" => "keyId=\"#{@certificate_id}\" algorithm=\"#{signature_algorithm}\" headers=\"#{headers_to_sign.join(" ")}\" signature=\"#{base64_signature}\""
|
86
|
-
}
|
87
|
-
end
|
88
93
|
end
|
89
94
|
end
|
data/lib/ibanity/util.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
module Ibanity
|
2
2
|
module Util
|
3
|
-
def self.
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
def self.underscorize(obj)
|
4
|
+
case obj
|
5
|
+
when Array
|
6
|
+
obj.map { |e| underscorize(e) }
|
7
|
+
when Hash
|
8
|
+
obj.keys.reduce({}) do |result, key|
|
9
|
+
result[underscore(key)] = underscorize(obj[key])
|
10
|
+
result
|
11
|
+
end
|
12
|
+
else
|
13
|
+
obj
|
7
14
|
end
|
8
15
|
end
|
9
16
|
|
data/lib/ibanity/version.rb
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "ibanity/http_signature"
|
2
|
+
|
3
|
+
RSpec.describe Ibanity::HttpSignature do
|
4
|
+
|
5
|
+
describe ".signature_headers" do
|
6
|
+
let(:signature) do
|
7
|
+
Ibanity::HttpSignature.new(
|
8
|
+
certificate: CryptoHelper.load_certificate("test"),
|
9
|
+
certificate_id: "ec0c29ef-3b39-4b6f-93ff-866bed032399",
|
10
|
+
key: CryptoHelper.load_private_key("test"),
|
11
|
+
method: "post",
|
12
|
+
uri: "https://api.ibanity.com/xs2a/customer-access-tokens",
|
13
|
+
headers: {"ibanity-idempotency-key" => "cf17b515-5f6f-4213-a8fe-e4cd40653d00"},
|
14
|
+
payload: "{\"foo\": \"bar\"}",
|
15
|
+
query_params: {}
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:parts_regex) do
|
20
|
+
/keyId="(?<keyId>.*)",\s?created="(?<created>.*)?",?\s?algorithm="(?<algorithm>.*)",\s?headers="(?<headers>.*)",?\s?signature="(?<signature>.*)"/
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:signature_parts) do
|
24
|
+
signature.signature_headers["Signature"].match(parts_regex).named_captures
|
25
|
+
end
|
26
|
+
|
27
|
+
["Digest", "Signature"].each do |header|
|
28
|
+
it "contains the '#{header}' header" do
|
29
|
+
expect(signature.signature_headers).to include(header)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
["keyId", "algorithm", "headers", "signature", "created"].each do |part|
|
34
|
+
it "has a signature containing the part '#{part}'" do
|
35
|
+
expect(signature_parts).to include(part)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'ibanity/util'
|
2
|
+
|
3
|
+
RSpec.describe Ibanity::Util do
|
4
|
+
describe ".underscorize" do
|
5
|
+
it "transforms all keys to snake_case" do
|
6
|
+
hash = {
|
7
|
+
"currency" => "EUR",
|
8
|
+
"amount" => 1,
|
9
|
+
"debtorName" => "Sophie Schowalter",
|
10
|
+
"debtorAccountReference" => "BE59823362319793",
|
11
|
+
}
|
12
|
+
|
13
|
+
expected = {
|
14
|
+
"currency" => "EUR",
|
15
|
+
"amount" => 1,
|
16
|
+
"debtor_name" => "Sophie Schowalter",
|
17
|
+
"debtor_account_reference" => "BE59823362319793",
|
18
|
+
}
|
19
|
+
|
20
|
+
expect(Ibanity::Util.underscorize(hash)).to eq(expected)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "processes hashes recursively" do
|
24
|
+
hash = {
|
25
|
+
"currency" => "EUR",
|
26
|
+
"amount" => 1,
|
27
|
+
"debtorName" => "Sophie Schowalter",
|
28
|
+
"details" => {
|
29
|
+
"debtorAccountReference" => "BE59823362319793"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
expected = {
|
34
|
+
"currency" => "EUR",
|
35
|
+
"amount" => 1,
|
36
|
+
"debtor_name" => "Sophie Schowalter",
|
37
|
+
"details" => {
|
38
|
+
"debtor_account_reference" => "BE59823362319793"
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
expect(Ibanity::Util.underscorize(hash)).to eq(expected)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "processes each array element" do
|
46
|
+
hash = {
|
47
|
+
"currency" => "EUR",
|
48
|
+
"amount" => 1,
|
49
|
+
"debtorName" => "Sophie Schowalter",
|
50
|
+
"details" => [
|
51
|
+
{"debtorAccountReference" => "BE59823362319793"}
|
52
|
+
]
|
53
|
+
}
|
54
|
+
|
55
|
+
expected = {
|
56
|
+
"currency" => "EUR",
|
57
|
+
"amount" => 1,
|
58
|
+
"debtor_name" => "Sophie Schowalter",
|
59
|
+
"details" => [
|
60
|
+
{"debtor_account_reference" => "BE59823362319793"}
|
61
|
+
]
|
62
|
+
}
|
63
|
+
|
64
|
+
expect(Ibanity::Util.underscorize(hash)).to eq(expected)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "leaves arrays elements untouched if they are not themselves hashes or arrays" do
|
68
|
+
hash = {
|
69
|
+
"currency" => "EUR",
|
70
|
+
"amount" => 1,
|
71
|
+
"debtorName" => "Sophie Schowalter",
|
72
|
+
"details" => [
|
73
|
+
"BE59823362319793"
|
74
|
+
]
|
75
|
+
}
|
76
|
+
|
77
|
+
expected = {
|
78
|
+
"currency" => "EUR",
|
79
|
+
"amount" => 1,
|
80
|
+
"debtor_name" => "Sophie Schowalter",
|
81
|
+
"details" => [
|
82
|
+
"BE59823362319793"
|
83
|
+
]
|
84
|
+
}
|
85
|
+
|
86
|
+
expect(Ibanity::Util.underscorize(hash)).to eq(expected)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
4
|
+
# this file to always be loaded, without a need to explicitly require it in any
|
5
|
+
# files.
|
6
|
+
#
|
7
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
8
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
9
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
10
|
+
# individual file that may not need all of that loaded. Instead, consider making
|
11
|
+
# a separate helper file that requires the additional dependencies and performs
|
12
|
+
# the additional setup, and require it from the spec files that actually need
|
13
|
+
# it.
|
14
|
+
#
|
15
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
16
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
# rspec-expectations config goes here. You can use an alternate
|
20
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
21
|
+
# assertions if you prefer.
|
22
|
+
config.expect_with :rspec do |expectations|
|
23
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
24
|
+
# and `failure_message` of custom matchers include text for helper methods
|
25
|
+
# defined using `chain`, e.g.:
|
26
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
27
|
+
# # => "be bigger than 2 and smaller than 4"
|
28
|
+
# ...rather than:
|
29
|
+
# # => "be bigger than 2"
|
30
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
31
|
+
end
|
32
|
+
|
33
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
34
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
35
|
+
config.mock_with :rspec do |mocks|
|
36
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
37
|
+
# a real object. This is generally recommended, and will default to
|
38
|
+
# `true` in RSpec 4.
|
39
|
+
mocks.verify_partial_doubles = true
|
40
|
+
end
|
41
|
+
|
42
|
+
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
43
|
+
# have no way to turn it off -- the option exists only for backwards
|
44
|
+
# compatibility in RSpec 3). It causes shared context metadata to be
|
45
|
+
# inherited by the metadata hash of host groups and examples, rather than
|
46
|
+
# triggering implicit auto-inclusion in groups with matching metadata.
|
47
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
48
|
+
|
49
|
+
# The settings below are suggested to provide a good initial experience
|
50
|
+
# with RSpec, but feel free to customize to your heart's content.
|
51
|
+
=begin
|
52
|
+
# This allows you to limit a spec run to individual examples or groups
|
53
|
+
# you care about by tagging them with `:focus` metadata. When nothing
|
54
|
+
# is tagged with `:focus`, all examples get run. RSpec also provides
|
55
|
+
# aliases for `it`, `describe`, and `context` that include `:focus`
|
56
|
+
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
57
|
+
config.filter_run_when_matching :focus
|
58
|
+
|
59
|
+
# Allows RSpec to persist some state between runs in order to support
|
60
|
+
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
61
|
+
# you configure your source control system to ignore this file.
|
62
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
63
|
+
|
64
|
+
# Limits the available syntax to the non-monkey patched syntax that is
|
65
|
+
# recommended. For more details, see:
|
66
|
+
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
67
|
+
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
68
|
+
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
69
|
+
config.disable_monkey_patching!
|
70
|
+
|
71
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
72
|
+
# be too noisy due to issues in dependencies.
|
73
|
+
config.warnings = true
|
74
|
+
|
75
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
76
|
+
# file, and it's useful to allow more verbose output when running an
|
77
|
+
# individual spec file.
|
78
|
+
if config.files_to_run.one?
|
79
|
+
# Use the documentation formatter for detailed output,
|
80
|
+
# unless a formatter has already been configured
|
81
|
+
# (e.g. via a command-line flag).
|
82
|
+
config.default_formatter = "doc"
|
83
|
+
end
|
84
|
+
|
85
|
+
# Print the 10 slowest examples and example groups at the
|
86
|
+
# end of the spec run, to help surface which specs are running
|
87
|
+
# particularly slow.
|
88
|
+
config.profile_examples = 10
|
89
|
+
|
90
|
+
# Run specs in random order to surface order dependencies. If you find an
|
91
|
+
# order dependency and want to debug it, you can fix the order by providing
|
92
|
+
# the seed, which is printed after each run.
|
93
|
+
# --seed 1234
|
94
|
+
config.order = :random
|
95
|
+
|
96
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
97
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
98
|
+
# test failures related to randomization by passing the same `--seed` value
|
99
|
+
# as the one that triggered the failure.
|
100
|
+
Kernel.srand config.seed
|
101
|
+
=end
|
102
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "openssl"
|
3
|
+
|
4
|
+
module CryptoHelper
|
5
|
+
FIXTURE_DIRECTORY = Pathname.getwd().join("spec", "support", "fixtures", "signature")
|
6
|
+
|
7
|
+
def self.load_certificate(name)
|
8
|
+
pem = File.read(FIXTURE_DIRECTORY.join("#{name}-certificate.pem"))
|
9
|
+
::OpenSSL::X509::Certificate.new(pem)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.load_public_key(name)
|
13
|
+
pem = File.read(FIXTURE_DIRECTORY.join("#{name}-public_key.pem"))
|
14
|
+
::OpenSSL::PKey::RSA.new(pem)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.load_private_key(name)
|
18
|
+
pem = File.read(FIXTURE_DIRECTORY.join("#{name}-private_key.pem"))
|
19
|
+
::OpenSSL::PKey::RSA.new(pem)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDdjCCAl4CCQCxpvuEfl5slTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJC
|
3
|
+
RTERMA8GA1UECAwIQnJ1c3NlbHMxETAPBgNVBAcMCEJydXNzZWxzMRAwDgYDVQQK
|
4
|
+
DAdJYmFuaXR5MRMwEQYDVQQDDAppYmFuaXR5LmJlMSEwHwYJKoZIhvcNAQkBFhJj
|
5
|
+
b21wYW55QGliYW5pdHkuYmUwHhcNMTkwNjI3MTE1NjAyWhcNMjkwNjI0MTE1NjAy
|
6
|
+
WjB9MQswCQYDVQQGEwJCRTERMA8GA1UECAwIQnJ1c3NlbHMxETAPBgNVBAcMCEJy
|
7
|
+
dXNzZWxzMRAwDgYDVQQKDAdJYmFuaXR5MRMwEQYDVQQDDAppYmFuaXR5LmJlMSEw
|
8
|
+
HwYJKoZIhvcNAQkBFhJjb21wYW55QGliYW5pdHkuYmUwggEiMA0GCSqGSIb3DQEB
|
9
|
+
AQUAA4IBDwAwggEKAoIBAQDcaDiqP4EkTYXzDqCLZGiEEQnx0iazY/f3IMZNnYVf
|
10
|
+
BDSLl3m2x1+3ch4Pe/E35Aag1webnvDh/VVRch0+n4KV/4Toe0Oq9VP6xKqOXYtZ
|
11
|
+
ZAVWXzs1TjdT/dk+rRXa+wnyq2KklPJ0aowzAyr3EzivW1v19uhWdqguhPEPopr/
|
12
|
+
2sue3vloZrigamOov29iFkiFLtSqAyEZI7x48w/3X2nkZ1UivYxBRrLnulVMUJDZ
|
13
|
+
zvydu3stlu6mSlaQ3Mpdgzyz4V41NImzNeJnW1F6riwd6hud9xokDZSvredC/XhM
|
14
|
+
byl0LdrKABzyHnOFSBlIkIHDeQUPa9YKBESRMtOVmyrvAgMBAAEwDQYJKoZIhvcN
|
15
|
+
AQELBQADggEBAKMwFzfoXXxasB/6ZlnAMy7aWmb8xp55E6aZZoZXhoHHA03z+Jj2
|
16
|
+
cVy/PMgNDOk5MLf4ddpj7iVf42iLAGpgqo0oQjE11UCwYBBDIQ3vjR+MctoN2B+L
|
17
|
+
Qpx7OGDoqSnVucVTS9KmWbJM3PAfbeexSRfqRJ3Jn2DvQDx1k32L//KtP1FRMtku
|
18
|
+
Dqoizz7NSLjrmIkXLAuepKdfDSVKnLHD1fB6gKvDNPBNivlFqceZe0XoXdlGwZcC
|
19
|
+
7aTdzYzZNCbg1w1bTxv7dom3ubAM1DPKUEA3afW25691ZsBf9W52hb/tOlVOw78j
|
20
|
+
+gUJtiEKTkcfmrfCgPDrcDjsm+iaQclAhK4=
|
21
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,28 @@
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcaDiqP4EkTYXz
|
3
|
+
DqCLZGiEEQnx0iazY/f3IMZNnYVfBDSLl3m2x1+3ch4Pe/E35Aag1webnvDh/VVR
|
4
|
+
ch0+n4KV/4Toe0Oq9VP6xKqOXYtZZAVWXzs1TjdT/dk+rRXa+wnyq2KklPJ0aowz
|
5
|
+
Ayr3EzivW1v19uhWdqguhPEPopr/2sue3vloZrigamOov29iFkiFLtSqAyEZI7x4
|
6
|
+
8w/3X2nkZ1UivYxBRrLnulVMUJDZzvydu3stlu6mSlaQ3Mpdgzyz4V41NImzNeJn
|
7
|
+
W1F6riwd6hud9xokDZSvredC/XhMbyl0LdrKABzyHnOFSBlIkIHDeQUPa9YKBESR
|
8
|
+
MtOVmyrvAgMBAAECggEAOS3olXJIJIzgFUBUMhVob+qjs9KbK6rhp4EfMP+OnCnR
|
9
|
+
H+26K8rpcAPw/H9hAujrN0rRtHO1dktsmOaL47UqAZP6fP2NfoqKsOHYhXqLLjOe
|
10
|
+
ltu51ohmHioa9AGfS+IYoJYJzzy88aq6mHlX6iVYbVW8M8FMYTIDS549k5rRr1Iu
|
11
|
+
SqGQSoIo8vGKhMyp6UbIvBhx1CRs2xeoknL0H5uEHnqB6oJTqfnbkQ1sVX4vZuHl
|
12
|
+
+WOIKQPlFKy74Lcs9ap1Dr9llD/PoVB3b2KbLRJTda352ezMLspb6CVUOFw7S0eB
|
13
|
+
vHVFlR+V922GaMvEmxZ58ZY+DwqBGPeuiG7/kYFNAQKBgQD8e64NptLgw7Wk8mvn
|
14
|
+
tGTB28ycUkc9wT/NdiePqlUT56ynD4oCBGcbEu6hH5ntYR93Kpi7fINTKglkVGdK
|
15
|
+
MkU/QOV0bs7wItqmQvkMeUbypnWXeQPICs3z/synytwbDYl7/FslTPxdjAgodQZJ
|
16
|
+
FY3Lui9bqe05VjvefEtEb9/yrwKBgQDfeimt/bVmA6Ldg4k+K72aAwP+g8l8Dyg1
|
17
|
+
Fba2vSFoS/MyvhCqTgP6Uh2fl8qXOqGJEv0koD3yRADa5/FlHSCeLhsyYqsLd/Zm
|
18
|
+
0Ogts7dhVm2v9jvVdmnWUQnGp/mPAGX6gB6Q1WHHEAdUNp6qAG7GatrJcttU0+7U
|
19
|
+
9cYKyc9bwQKBgC7oi53dsLAxrD3JDGMwEMgzngAtCS9gCAqUOSVn8AaStHEVYf6d
|
20
|
+
8soE6nDk/iQsNzxcnaO3rm51EOmjBM20KUlnNTo8nBXhY94f80VuAtByPMa3pQw1
|
21
|
+
da4vWLaT6fDcwv5WFFkJxJlcuudJVrGdX4rKPKI7H+fXLahYT2OXpXPhAoGBAIO9
|
22
|
+
Vli1WXw75ITFB+DYlDr4UCB3vA0gOkmg9Ucgk1MSgtmE5fofZ4TnZ4MvTkR8UcGm
|
23
|
+
qggvVpU8tWxWkx1SYGofL/Ux6Tcnjt/pgxV9/jqpYpv6gidCWP34Y9TyLNG6IGPd
|
24
|
+
pycmQy/AKTHhyQLaonLhhvx+cwG8texgvlCZy12BAoGAYsahYudgvuUi/IKjQvkH
|
25
|
+
0F/kwBnd0mRHttsEMIVjrG1Y82EUh5Ja05IGpOSSMeBVhIlJ/DnwFOoSmIVzGfsA
|
26
|
+
4GHtXmHd1xByxjW4nbr4NH7u8ElULkOPjcxSLgXhDb5KtG1XwCPEMUqvApcM6cfv
|
27
|
+
CQn8vQRR2J42gXEcTmt0zVQ=
|
28
|
+
-----END PRIVATE KEY-----
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
2
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3Gg4qj+BJE2F8w6gi2Ro
|
3
|
+
hBEJ8dIms2P39yDGTZ2FXwQ0i5d5tsdft3IeD3vxN+QGoNcHm57w4f1VUXIdPp+C
|
4
|
+
lf+E6HtDqvVT+sSqjl2LWWQFVl87NU43U/3ZPq0V2vsJ8qtipJTydGqMMwMq9xM4
|
5
|
+
r1tb9fboVnaoLoTxD6Ka/9rLnt75aGa4oGpjqL9vYhZIhS7UqgMhGSO8ePMP919p
|
6
|
+
5GdVIr2MQUay57pVTFCQ2c78nbt7LZbupkpWkNzKXYM8s+FeNTSJszXiZ1tReq4s
|
7
|
+
HeobnfcaJA2Ur63nQv14TG8pdC3aygAc8h5zhUgZSJCBw3kFD2vWCgREkTLTlZsq
|
8
|
+
7wIDAQAB
|
9
|
+
-----END PUBLIC KEY-----
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ibanity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ibanity
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -30,28 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 3.
|
33
|
+
version: 3.9.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 3.
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: webmock
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - '='
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 1.24.2
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - '='
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 1.24.2
|
40
|
+
version: 3.9.0
|
55
41
|
description: A Ruby wrapper for the Ibanity API.
|
56
42
|
email:
|
57
43
|
- info@ibanity.com
|
@@ -61,6 +47,9 @@ extra_rdoc_files: []
|
|
61
47
|
files:
|
62
48
|
- ".gitignore"
|
63
49
|
- ".gitkeep"
|
50
|
+
- ".rspec"
|
51
|
+
- ".travis.yml"
|
52
|
+
- CHANGELOG.md
|
64
53
|
- Gemfile
|
65
54
|
- LICENSE.txt
|
66
55
|
- README.md
|
@@ -81,10 +70,15 @@ files:
|
|
81
70
|
- lib/ibanity/api/o_auth_resource.rb
|
82
71
|
- lib/ibanity/api/ponto_connect/account.rb
|
83
72
|
- lib/ibanity/api/ponto_connect/financial_institution.rb
|
73
|
+
- lib/ibanity/api/ponto_connect/integration.rb
|
84
74
|
- lib/ibanity/api/ponto_connect/payment.rb
|
75
|
+
- lib/ibanity/api/ponto_connect/sandbox/financial_institution_account.rb
|
76
|
+
- lib/ibanity/api/ponto_connect/sandbox/financial_institution_transaction.rb
|
85
77
|
- lib/ibanity/api/ponto_connect/synchronization.rb
|
86
78
|
- lib/ibanity/api/ponto_connect/token.rb
|
87
79
|
- lib/ibanity/api/ponto_connect/transaction.rb
|
80
|
+
- lib/ibanity/api/ponto_connect/usage.rb
|
81
|
+
- lib/ibanity/api/ponto_connect/user_info.rb
|
88
82
|
- lib/ibanity/api/sandbox/financial_institution_account.rb
|
89
83
|
- lib/ibanity/api/sandbox/financial_institution_holding.rb
|
90
84
|
- lib/ibanity/api/sandbox/financial_institution_transaction.rb
|
@@ -92,12 +86,15 @@ files:
|
|
92
86
|
- lib/ibanity/api/xs2a/account.rb
|
93
87
|
- lib/ibanity/api/xs2a/account_information_access_request.rb
|
94
88
|
- lib/ibanity/api/xs2a/account_information_access_request_authorization.rb
|
89
|
+
- lib/ibanity/api/xs2a/bulk_payment_initiation_request.rb
|
95
90
|
- lib/ibanity/api/xs2a/customer.rb
|
96
91
|
- lib/ibanity/api/xs2a/customer_access_token.rb
|
97
92
|
- lib/ibanity/api/xs2a/financial_institution.rb
|
93
|
+
- lib/ibanity/api/xs2a/financial_institution_country.rb
|
98
94
|
- lib/ibanity/api/xs2a/holding.rb
|
99
95
|
- lib/ibanity/api/xs2a/payment_initiation_request.rb
|
100
96
|
- lib/ibanity/api/xs2a/payment_initiation_request_authorization.rb
|
97
|
+
- lib/ibanity/api/xs2a/periodic_payment_initiation_request.rb
|
101
98
|
- lib/ibanity/api/xs2a/synchronization.rb
|
102
99
|
- lib/ibanity/api/xs2a/transaction.rb
|
103
100
|
- lib/ibanity/client.rb
|
@@ -106,6 +103,13 @@ files:
|
|
106
103
|
- lib/ibanity/http_signature.rb
|
107
104
|
- lib/ibanity/util.rb
|
108
105
|
- lib/ibanity/version.rb
|
106
|
+
- spec/lib/ibanity/http_signature_spec.rb
|
107
|
+
- spec/lib/ibanity/util_spec.rb
|
108
|
+
- spec/spec_helper.rb
|
109
|
+
- spec/support/crypto_helper.rb
|
110
|
+
- spec/support/fixtures/signature/test-certificate.pem
|
111
|
+
- spec/support/fixtures/signature/test-private_key.pem
|
112
|
+
- spec/support/fixtures/signature/test-public_key.pem
|
109
113
|
homepage: https://documentation.ibanity.com/api/ruby
|
110
114
|
licenses:
|
111
115
|
- MIT
|
@@ -125,8 +129,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
129
|
- !ruby/object:Gem::Version
|
126
130
|
version: '0'
|
127
131
|
requirements: []
|
128
|
-
rubygems_version: 3.0.
|
132
|
+
rubygems_version: 3.0.8
|
129
133
|
signing_key:
|
130
134
|
specification_version: 4
|
131
135
|
summary: Ibanity Ruby Client
|
132
|
-
test_files:
|
136
|
+
test_files:
|
137
|
+
- spec/lib/ibanity/http_signature_spec.rb
|
138
|
+
- spec/lib/ibanity/util_spec.rb
|
139
|
+
- spec/spec_helper.rb
|
140
|
+
- spec/support/crypto_helper.rb
|
141
|
+
- spec/support/fixtures/signature/test-certificate.pem
|
142
|
+
- spec/support/fixtures/signature/test-private_key.pem
|
143
|
+
- spec/support/fixtures/signature/test-public_key.pem
|