ibanity 1.7.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/gem-push.yml +1 -1
  3. data/CHANGELOG.md +28 -1
  4. data/ibanity.gemspec +1 -0
  5. data/lib/ibanity/api/base_resource.rb +50 -22
  6. data/lib/ibanity/api/flat_resource.rb +20 -0
  7. data/lib/ibanity/api/isabel_connect/access_token.rb +1 -0
  8. data/lib/ibanity/api/isabel_connect/bulk_payment_initiation_request.rb +4 -2
  9. data/lib/ibanity/api/isabel_connect/refresh_token.rb +3 -1
  10. data/lib/ibanity/api/isabel_connect/token.rb +39 -0
  11. data/lib/ibanity/api/ponto_connect/bulk_payment.rb +20 -0
  12. data/lib/ibanity/api/ponto_connect/payment_activation_request.rb +10 -0
  13. data/lib/ibanity/api/ponto_connect/reauthorization_request.rb +10 -0
  14. data/lib/ibanity/api/ponto_connect/sandbox/financial_institution_transaction.rb +8 -0
  15. data/lib/ibanity/api/sandbox/financial_institution_transaction.rb +10 -0
  16. data/lib/ibanity/api/webhooks/key.rb +11 -0
  17. data/lib/ibanity/api/webhooks/ponto_connect.rb +24 -0
  18. data/lib/ibanity/api/webhooks/xs2a.rb +24 -0
  19. data/lib/ibanity/api/xs2a/transaction.rb +10 -5
  20. data/lib/ibanity/client.rb +83 -9
  21. data/lib/ibanity/error.rb +2 -0
  22. data/lib/ibanity/http_signature.rb +28 -5
  23. data/lib/ibanity/version.rb +1 -1
  24. data/lib/ibanity/webhook.rb +94 -0
  25. data/lib/ibanity.rb +24 -3
  26. data/spec/lib/ibanity/base_resource_spec.rb +42 -0
  27. data/spec/spec_helper.rb +6 -0
  28. data/spec/support/fixture.rb +8 -0
  29. data/spec/support/fixtures/json/relationships/data_with_type.json +21 -0
  30. data/spec/support/fixtures/json/relationships/data_without_type.json +20 -0
  31. data/spec/support/fixtures/json/relationships/meta_with_type.json +20 -0
  32. data/spec/support/fixtures/json/relationships/no_links_related.json +15 -0
  33. metadata +38 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7fd6f89318c851b7400543ff611a42ae6212bd62ce5073422d1bd36c822369a
4
- data.tar.gz: c8fe8aaf323a55636815cd8c6669192005eb358fc396bb9e0528add3790ba3e3
3
+ metadata.gz: f0b9e9d3d5bd37f738613c1e77292d6cee3fcbf5016d3d5200d7f4715d673735
4
+ data.tar.gz: a757cd1e70e6588174e56de7584d10f04b1b2023c6cf9e0c02e5377c8b6a226b
5
5
  SHA512:
6
- metadata.gz: 4190b626cf11725cd578cf7865307eb65610bf98e4c6c89f47e3559a679d8e07be9423b0dc44263c23b07361f6d050b0fface497077c26dfa30cd41c39dcfa06
7
- data.tar.gz: 19e030f8f098906171c1784c88b25a58e51f486b15c8cdad4e8ca61ddba81b18d83684478c6e77681d4f28c287762f256228c24876261fe924d5af4f025dd364
6
+ metadata.gz: 6c9b41e71c94eac22e8416d5689bb1c02c6cee7c1ba73a0fad1da4d6154a3bd18e7ae16baf154b3e5d881a72e18d77e991580f3dd3486ceb5a5fa157b1b652cd
7
+ data.tar.gz: 6fbd44ba0f4d06bb8e890728311bdf8f28e00008688f6d9005e9da6c55377e98644f1e0d8890543a69de7884a83ed6cfabe1e97f01cf381067ad84a801878bd6
@@ -2,7 +2,7 @@ name: Ruby Gem
2
2
 
3
3
  on:
4
4
  release:
5
- types: [created]
5
+ types: [published]
6
6
 
7
7
  jobs:
8
8
  build:
data/CHANGELOG.md CHANGED
@@ -1,4 +1,31 @@
1
1
  # Changelog
2
+
3
+ ## 1.11
4
+
5
+ * Allow to tweak RestClient's timeout.
6
+
7
+ ## 1.10
8
+
9
+ * [Ponto Connect] Add support for payment activation requests.
10
+
11
+ * [Webhooks] Add support for webhook signature validation, keys endpoint, and events.
12
+
13
+ ## 1.9
14
+
15
+ * [Ponto Connect] Add account reauthorization requests
16
+
17
+ * [Isabel Connect] Deprecate `Ibanity::IsabelConnect::AccessToken` and `Ibanity::IsabelConnect::RefreshToken`, please use `Ibanity::IsabelConnect::Token` instead
18
+
19
+ ## 1.8
20
+
21
+ * [XS2A] Update sandbox transactions
22
+
23
+ * [XS2A] Add support to list updated transaction using `synchronization_id`
24
+
25
+ * [Ponto Connect] Add support to BulkPayments
26
+
27
+ * [Isabel Connect] Add `hideDetails` and `isShared` parameters to `BulkPaymentInititationRequest.create`
28
+
2
29
  ## 1.7
3
30
  ### Enhancements
4
31
 
@@ -29,7 +56,7 @@
29
56
 
30
57
  ### Enhancements
31
58
 
32
- * Default signature algorithm is now ["hs2019"](https://tools.ietf.org/html/draft-cavage-http-signatures-12#appendix-E.2)
59
+ * Default signature algorithm is now ["hs2019"](https://tools.ietf.org/html/draft-cavage-http-signatures-12#appendix-E.2)
33
60
  * Add support for periodic and bulk payments
34
61
  * Add snake-case transformation for deeply nested data structures
35
62
 
data/ibanity.gemspec CHANGED
@@ -19,5 +19,6 @@ 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_dependency "jose", ">= 1.1.3"
22
23
  spec.add_development_dependency "rspec", "3.9.0"
23
24
  end
@@ -86,6 +86,8 @@ module Ibanity
86
86
  private
87
87
 
88
88
  def prepare_attributes(raw)
89
+ raise "Unexpected raw type, expected hash, got #{raw}" unless raw.is_a?(Hash)
90
+
89
91
  base = {
90
92
  "id" => raw["id"],
91
93
  }
@@ -97,23 +99,47 @@ module Ibanity
97
99
 
98
100
  def setup_relationships(relationships, customer_access_token = nil)
99
101
  relationships.each do |key, relationship|
100
- if relationship["data"]
101
- self[Ibanity::Util.underscore("#{key}_id")] = relationship["data"]["id"]
102
- return unless relationship.dig("links", "related")
103
-
104
- klass = relationship_klass(key)
105
- method_name = Ibanity::Util.underscore(key)
106
- define_singleton_method(method_name) do |headers: nil|
107
- klass.find_by_uri(uri: relationship["links"]["related"], headers: headers, customer_access_token: customer_access_token)
108
- end
109
- else
110
- singular_key = key[0..-2]
111
- klass = relationship_klass(singular_key)
112
- method_name = Ibanity::Util.underscore(key)
113
- define_singleton_method(method_name) do |headers: nil, **query_params|
114
- uri = relationship["links"]["related"]
115
- klass.list_by_uri(uri: uri, headers: headers, query_params: query_params, customer_access_token: customer_access_token)
116
- end
102
+ url = relationship.dig("links", "related")
103
+ id = relationship.dig("data", "id")
104
+
105
+ if url
106
+ setup_relationship(customer_access_token, key, relationship, url)
107
+ elsif id
108
+ self[Ibanity::Util.underscore("#{key}_id")] = id
109
+ end
110
+ end
111
+ end
112
+
113
+ def setup_relationship(customer_access_token, key, relationship, url)
114
+ if relationship["data"]
115
+ resource = relationship.dig("data", "type") || key
116
+ klass = relationship_klass(resource)
117
+ method_name = Ibanity::Util.underscore(key)
118
+ define_singleton_method(method_name) do |headers: nil|
119
+ klass.find_by_uri(uri: url, headers: headers, customer_access_token: customer_access_token)
120
+ end
121
+ self[Ibanity::Util.underscore("#{key}_id")] = relationship.dig("data", "id")
122
+ elsif relationship["meta"]
123
+ resource = relationship.dig("meta", "type")
124
+ klass = relationship_klass(resource)
125
+ method_name = Ibanity::Util.underscore(key)
126
+ define_singleton_method(method_name) do |headers: nil|
127
+ klass.find_by_uri(uri: url, headers: headers, customer_access_token: customer_access_token)
128
+ end
129
+ elsif relationship.dig("links", "meta", "type")
130
+ resource = relationship.dig("links", "meta", "type")
131
+ klass = relationship_klass(resource)
132
+ method_name = Ibanity::Util.underscore(key)
133
+ define_singleton_method(method_name) do |headers: nil, **query_params|
134
+ klass.list_by_uri(uri: url, headers: headers, query_params: query_params, customer_access_token: customer_access_token)
135
+ end
136
+ else
137
+ resource = key
138
+ singular_resource = resource[0..-2]
139
+ klass = relationship_klass(singular_resource)
140
+ method_name = Ibanity::Util.underscore(resource)
141
+ define_singleton_method(method_name) do |headers: nil, **query_params|
142
+ klass.list_by_uri(uri: url, headers: headers, query_params: query_params, customer_access_token: customer_access_token)
117
143
  end
118
144
  end
119
145
  end
@@ -126,11 +152,13 @@ module Ibanity
126
152
 
127
153
  def relationship_klass(name)
128
154
  camelized_name = Ibanity::Util.camelize(name)
129
- enclosing_module = if camelized_name == "FinancialInstitution"
130
- Ibanity::Xs2a
131
- else
132
- Object.const_get(self.class.to_s.split("::")[0...-1].join("::"))
133
- end
155
+ enclosing_module =
156
+ if camelized_name == "FinancialInstitution"
157
+ Ibanity::Xs2a
158
+ else
159
+ Object.const_get(self.class.to_s.split("::")[0...-1].join("::"))
160
+ end
161
+
134
162
  enclosing_module.const_get(camelized_name)
135
163
  end
136
164
  end
@@ -0,0 +1,20 @@
1
+ module Ibanity
2
+ class FlatResource < OpenStruct
3
+ def self.list_by_uri(uri:, key:)
4
+ raw_response = Ibanity.client.get(uri: uri)
5
+ items = raw_response[key].map { |raw_item| new(raw_item) }
6
+ Ibanity::Collection.new(
7
+ klass: self,
8
+ items: items,
9
+ links: nil,
10
+ paging: nil,
11
+ synchronized_at: nil,
12
+ latest_synchronization: nil
13
+ )
14
+ end
15
+
16
+ def initialize(raw)
17
+ super(raw)
18
+ end
19
+ end
20
+ end
@@ -2,6 +2,7 @@ module Ibanity
2
2
  module IsabelConnect
3
3
  class AccessToken < Ibanity::OAuthResource
4
4
  def self.create(refresh_token:, idempotency_key: nil)
5
+ warn "WARNING: Ibanity::IsabelConnect::AccessToken.create is deprecated, please use Ibanity::IsabelConnect::Token.create instead"
5
6
  uri = Ibanity.isabel_connect_api_schema["oAuth2"]["accessTokens"]
6
7
  arguments = [
7
8
  ["grant_type", "refresh_token"],
@@ -1,7 +1,7 @@
1
1
  module Ibanity
2
2
  module IsabelConnect
3
3
  class BulkPaymentInitiationRequest < Ibanity::BaseResource
4
- def self.create(access_token:, raw_content:, filename:, idempotency_key: nil)
4
+ def self.create(access_token:, raw_content:, filename:, idempotency_key: nil, is_shared: true, hide_details: false)
5
5
  uri = Ibanity.isabel_connect_api_schema["bulkPaymentInitiationRequests"].sub("{bulkPaymentInitiationRequestId}", "")
6
6
  create_file_by_uri(
7
7
  uri: uri,
@@ -11,7 +11,9 @@ module Ibanity
11
11
  idempotency_key: idempotency_key,
12
12
  headers: {
13
13
  content_type: :xml,
14
- "Content-Disposition": "inline; filename=#{filename}"
14
+ "Content-Disposition": "inline; filename=#{filename}",
15
+ "Is-Shared": is_shared,
16
+ "Hide-Details": hide_details
15
17
  }
16
18
  )
17
19
  end
@@ -2,6 +2,7 @@ module Ibanity
2
2
  module IsabelConnect
3
3
  class RefreshToken < Ibanity::OAuthResource
4
4
  def self.create(authorization_code:, redirect_uri:, idempotency_key: nil)
5
+ warn "WARNING: Ibanity::IsabelConnect::RefreshToken.create is deprecated, please use Ibanity::IsabelConnect::Token.create instead"
5
6
  uri = Ibanity.isabel_connect_api_schema["oAuth2"]["refreshTokens"]["create"]
6
7
  arguments = [
7
8
  ["grant_type", "authorization_code"],
@@ -13,8 +14,9 @@ module Ibanity
13
14
  payload = URI.encode_www_form(arguments)
14
15
  create_by_uri(uri: uri, payload: payload, idempotency_key: idempotency_key)
15
16
  end
16
-
17
+
17
18
  def self.delete(token:)
19
+ warn "WARNING: Ibanity::IsabelConnect::RefreshToken.delete is deprecated, please use Ibanity::IsabelConnect::Token.delete instead"
18
20
  uri = Ibanity.isabel_connect_api_schema["oAuth2"]["refreshTokens"]["revoke"]
19
21
  arguments = [
20
22
  ["token", token],
@@ -0,0 +1,39 @@
1
+ module Ibanity
2
+ module IsabelConnect
3
+ class Token < Ibanity::OAuthResource
4
+ def self.create(refresh_token: nil, authorization_code: nil, redirect_uri: nil, idempotency_key: nil)
5
+ uri = Ibanity.isabel_connect_api_schema["oAuth2"]["token"]
6
+ arguments =
7
+ if refresh_token
8
+ [
9
+ ["grant_type", "refresh_token"],
10
+ ["refresh_token", refresh_token],
11
+ ["client_id", Ibanity.client.isabel_connect_client_id],
12
+ ["client_secret", Ibanity.client.isabel_connect_client_secret]
13
+ ]
14
+ elsif authorization_code
15
+ [
16
+ ["grant_type", "authorization_code"],
17
+ ["code", authorization_code],
18
+ ["client_id", Ibanity.client.isabel_connect_client_id],
19
+ ["client_secret", Ibanity.client.isabel_connect_client_secret],
20
+ ["redirect_uri", redirect_uri]
21
+ ]
22
+ end
23
+ payload = URI.encode_www_form(arguments)
24
+ create_by_uri(uri: uri, payload: payload, idempotency_key: idempotency_key)
25
+ end
26
+
27
+ def self.delete(token:)
28
+ uri = Ibanity.isabel_connect_api_schema["oAuth2"]["revoke"]
29
+ arguments = [
30
+ ["token", token],
31
+ ["client_id", Ibanity.client.isabel_connect_client_id],
32
+ ["client_secret", Ibanity.client.isabel_connect_client_secret]
33
+ ]
34
+ payload = URI.encode_www_form(arguments)
35
+ create_by_uri(uri: uri, payload: payload)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,20 @@
1
+ module Ibanity
2
+ module PontoConnect
3
+ class BulkPayment < Ibanity::BaseResource
4
+ def self.find(access_token:, account_id:, id:)
5
+ uri = Ibanity.ponto_connect_api_schema["account"]["bulkPayments"].sub("{accountId}", account_id).sub("{bulkPaymentId}", id)
6
+ find_by_uri(uri: uri, customer_access_token: access_token)
7
+ end
8
+
9
+ def self.create(account_id:, access_token: nil, **attributes)
10
+ uri = Ibanity.ponto_connect_api_schema["account"]["bulkPayments"].gsub("{accountId}", account_id).gsub("{bulkPaymentId}", "")
11
+ create_by_uri(uri: uri, resource_type: "bulkPayment", attributes: attributes, customer_access_token: access_token)
12
+ end
13
+
14
+ def self.delete(id:, account_id:, access_token:)
15
+ uri = Ibanity.ponto_connect_api_schema["account"]["bulkPayments"].gsub("{accountId}", account_id).gsub("{bulkPaymentId}", id)
16
+ destroy_by_uri(uri: uri, customer_access_token: access_token)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ module Ibanity
2
+ module PontoConnect
3
+ class PaymentActivationRequest < Ibanity::BaseResource
4
+ def self.create(access_token:, **attributes)
5
+ uri = Ibanity.ponto_connect_api_schema["paymentActivationRequests"]
6
+ create_by_uri(uri: uri, resource_type: "paymentActivationRequest", attributes: attributes, customer_access_token: access_token)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Ibanity
2
+ module PontoConnect
3
+ class ReauthorizationRequest < Ibanity::BaseResource
4
+ def self.create(account_id:, access_token:, **attributes)
5
+ uri = Ibanity.ponto_connect_api_schema["account"]["reauthorizationRequests"].gsub("{accountId}", account_id)
6
+ create_by_uri(uri: uri, resource_type: "reauthorizationRequest", attributes: attributes, customer_access_token: access_token)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -25,6 +25,14 @@ module Ibanity
25
25
  .sub("{financialInstitutionTransactionId}", "")
26
26
  create_by_uri(uri: uri, resource_type: "financialInstitutionTransaction", attributes: attributes, customer_access_token: access_token)
27
27
  end
28
+
29
+ def self.update(access_token:, id:, financial_institution_id:, financial_institution_account_id:, **attributes)
30
+ uri = Ibanity.ponto_connect_api_schema["sandbox"]["financialInstitution"]["financialInstitutionAccount"]["financialInstitutionTransactions"]
31
+ .sub("{financialInstitutionId}", financial_institution_id)
32
+ .sub("{financialInstitutionAccountId}", financial_institution_account_id)
33
+ .sub("{financialInstitutionTransactionId}", id)
34
+ update_by_uri(uri: uri, resource_type: "financialInstitutionTransaction", attributes: attributes, customer_access_token: access_token)
35
+ end
28
36
  end
29
37
  end
30
38
  end
@@ -31,6 +31,16 @@ module Ibanity
31
31
  find_by_uri(uri: uri)
32
32
  end
33
33
 
34
+ def self.update(id:, financial_institution_user_id:, financial_institution_id:, financial_institution_account_id:, idempotency_key: nil, **attributes)
35
+ path = Ibanity.sandbox_api_schema["financialInstitution"]["financialInstitutionAccount"]["financialInstitutionTransactions"]
36
+ .gsub("{financialInstitutionId}", financial_institution_id)
37
+ .gsub("{financialInstitutionUserId}", financial_institution_user_id)
38
+ .gsub("{financialInstitutionAccountId}", financial_institution_account_id)
39
+ .gsub("{financialInstitutionTransactionId}", id)
40
+ uri = Ibanity.client.build_uri(path)
41
+ update_by_uri(uri: uri, resource_type: "financialInstitutionTransaction", attributes: attributes, idempotency_key: idempotency_key)
42
+ end
43
+
34
44
  def self.delete(id:, financial_institution_user_id:, financial_institution_id:, financial_institution_account_id:)
35
45
  path = Ibanity.sandbox_api_schema["financialInstitution"]["financialInstitutionAccount"]["financialInstitutionTransactions"]
36
46
  .gsub("{financialInstitutionId}", financial_institution_id)
@@ -0,0 +1,11 @@
1
+ module Ibanity
2
+ module Webhooks
3
+ class Key < Ibanity::FlatResource
4
+ def self.list
5
+ path = Ibanity.webhooks_api_schema["keys"]
6
+ uri = Ibanity.client.build_uri(path)
7
+ list_by_uri(uri: uri, key: "keys")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module Ibanity
2
+ module Webhooks
3
+ module PontoConnect
4
+ module Synchronization
5
+ class SucceededWithoutChange < Ibanity::BaseResource
6
+ end
7
+
8
+ class Failed < Ibanity::BaseResource
9
+ end
10
+ end
11
+
12
+ module Account
13
+ class DetailsUpdated < Ibanity::BaseResource
14
+ end
15
+
16
+ class TransactionsCreated < Ibanity::BaseResource
17
+ end
18
+
19
+ class TransactionsUpdated < Ibanity::BaseResource
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ module Ibanity
2
+ module Webhooks
3
+ module Xs2a
4
+ module Synchronization
5
+ class SucceededWithoutChange < Ibanity::BaseResource
6
+ end
7
+
8
+ class Failed < Ibanity::BaseResource
9
+ end
10
+ end
11
+
12
+ module Account
13
+ class DetailsUpdated < Ibanity::BaseResource
14
+ end
15
+
16
+ class TransactionsCreated < Ibanity::BaseResource
17
+ end
18
+
19
+ class TransactionsUpdated < Ibanity::BaseResource
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,11 +1,16 @@
1
1
  module Ibanity
2
2
  module Xs2a
3
3
  class Transaction < Ibanity::BaseResource
4
- def self.list(financial_institution_id:, account_id:, customer_access_token:, headers: nil, **query_params)
5
- uri = Ibanity.xs2a_api_schema["customer"]["financialInstitution"]["transactions"]
6
- .sub("{financialInstitutionId}", financial_institution_id)
7
- .sub("{accountId}", account_id)
8
- .sub("{transactionId}", "")
4
+ def self.list(financial_institution_id: nil, account_id: nil, synchronization_id: nil, customer_access_token:, headers: nil, **query_params)
5
+ uri = if synchronization_id
6
+ Ibanity.xs2a_api_schema["customer"]["synchronization"]["updatedTransactions"]
7
+ .sub("{synchronizationId}", synchronization_id)
8
+ else
9
+ Ibanity.xs2a_api_schema["customer"]["financialInstitution"]["transactions"]
10
+ .sub("{financialInstitutionId}", financial_institution_id)
11
+ .sub("{accountId}", account_id)
12
+ .sub("{transactionId}", "")
13
+ end
9
14
  list_by_uri(uri: uri, query_params: query_params, customer_access_token: customer_access_token, headers: headers)
10
15
  end
11
16
 
@@ -1,22 +1,43 @@
1
1
  module Ibanity
2
2
  class Client
3
3
 
4
- attr_reader :base_uri, :signature_certificate, :signature_key, :isabel_connect_client_id, :isabel_connect_client_secret, :ponto_connect_client_id, :ponto_connect_client_secret
4
+ attr_reader :base_uri, :signature_certificate, :signature_key, :isabel_connect_client_id, :isabel_connect_client_secret, :ponto_connect_client_id, :ponto_connect_client_secret, :application_id
5
5
 
6
- def initialize(certificate:, key:, key_passphrase:, signature_certificate: nil, signature_certificate_id: nil, signature_key: nil, signature_key_passphrase: nil, api_scheme: "https", api_host: "api.ibanity.com", api_port: "443", ssl_ca_file: nil, isabel_connect_client_id: "valid_client_id", isabel_connect_client_secret: "valid_client_secret", ponto_connect_client_id: nil, ponto_connect_client_secret: nil)
6
+ def initialize(
7
+ certificate:,
8
+ key:,
9
+ key_passphrase:,
10
+ signature_certificate: nil,
11
+ signature_certificate_id: nil,
12
+ signature_key: nil,
13
+ signature_key_passphrase: nil,
14
+ api_scheme: "https",
15
+ api_host: "api.ibanity.com",
16
+ ssl_ca_file: nil,
17
+ isabel_connect_client_id: "valid_client_id",
18
+ isabel_connect_client_secret: "valid_client_secret",
19
+ ponto_connect_client_id: nil,
20
+ ponto_connect_client_secret: nil,
21
+ application_id: nil,
22
+ debug_http_requests: false,
23
+ timeout: 60
24
+ )
7
25
  @isabel_connect_client_id = isabel_connect_client_id
8
26
  @isabel_connect_client_secret = isabel_connect_client_secret
9
27
  @ponto_connect_client_id = ponto_connect_client_id
10
28
  @ponto_connect_client_secret = ponto_connect_client_secret
11
29
  @certificate = OpenSSL::X509::Certificate.new(certificate)
12
30
  @key = OpenSSL::PKey::RSA.new(key, key_passphrase)
31
+ @http_debug = debug_http_requests
13
32
  if signature_certificate
14
33
  @signature_certificate = OpenSSL::X509::Certificate.new(signature_certificate)
15
34
  @signature_certificate_id = signature_certificate_id
16
35
  @signature_key = OpenSSL::PKey::RSA.new(signature_key, signature_key_passphrase)
17
36
  end
18
- @base_uri = "#{api_scheme}://#{api_host}:#{api_port}"
37
+ @base_uri = "#{api_scheme}://#{api_host}"
19
38
  @ssl_ca_file = ssl_ca_file
39
+ @application_id = application_id
40
+ @timeout = timeout
20
41
  end
21
42
 
22
43
  def get(uri:, query_params: {}, customer_access_token: nil, headers: nil, json: true)
@@ -25,12 +46,12 @@ module Ibanity
25
46
  end
26
47
 
27
48
  def post(uri:, payload:, query_params: {}, customer_access_token: nil, idempotency_key: nil, json: true, headers: nil)
28
- headers = build_headers(customer_access_token: customer_access_token, idempotency_key: idempotency_key, extra_headers: headers, json: json)
49
+ headers = build_headers(customer_access_token: customer_access_token, idempotency_key: idempotency_key, extra_headers: headers, json: json, payload: payload)
29
50
  execute(method: :post, uri: uri, headers: headers, query_params: query_params, payload: payload, json: json)
30
51
  end
31
52
 
32
53
  def patch(uri:, payload:, query_params: {}, customer_access_token: nil, idempotency_key: nil, json: true)
33
- headers = build_headers(customer_access_token: customer_access_token, idempotency_key: idempotency_key, json: json)
54
+ headers = build_headers(customer_access_token: customer_access_token, idempotency_key: idempotency_key, json: json, payload: payload)
34
55
  execute(method: :patch, uri: uri, headers: headers, query_params: query_params, payload: payload, json: json)
35
56
  end
36
57
 
@@ -46,6 +67,15 @@ module Ibanity
46
67
  private
47
68
 
48
69
  def execute(method:, uri:, headers:, query_params: {}, payload: nil, json:)
70
+ case payload
71
+ when NilClass
72
+ payload = ''
73
+ when Hash
74
+ payload = json ? payload.to_json : payload
75
+ when Pathname
76
+ payload = File.open(payload, 'rb')
77
+ end
78
+
49
79
  if @signature_certificate
50
80
  signature = Ibanity::HttpSignature.new(
51
81
  certificate: @signature_certificate,
@@ -55,23 +85,31 @@ module Ibanity
55
85
  uri: uri,
56
86
  query_params: query_params,
57
87
  headers: headers,
58
- payload: payload && json ? payload.to_json : payload
88
+ payload: payload
59
89
  )
60
90
  headers.merge!(signature.signature_headers)
61
91
  end
92
+
62
93
  query = {
63
94
  method: method,
64
95
  url: uri,
65
96
  headers: headers.merge(params: query_params),
66
- payload: payload && json ? payload.to_json : payload,
97
+ payload: payload,
67
98
  ssl_client_cert: @certificate,
68
99
  ssl_client_key: @key,
69
- ssl_ca_file: @ssl_ca_file
100
+ ssl_ca_file: @ssl_ca_file,
101
+ timeout: @timeout
70
102
  }
103
+
104
+ log("HTTP Request", query) if @http_debug
105
+
71
106
  raw_response = RestClient::Request.execute(query) do |response, request, result, &block|
107
+ log("HTTP response", { status: response.code, headers: response.headers, body: response.body }) if @http_debug
108
+
72
109
  if response.code >= 400
73
110
  ibanity_request_id = response.headers[:ibanity_request_id]
74
111
  body = JSON.parse(response.body)
112
+
75
113
  raise Ibanity::Error.new(body["errors"] || body, ibanity_request_id), "Ibanity request failed."
76
114
  else
77
115
  response.return!(&block)
@@ -80,12 +118,15 @@ module Ibanity
80
118
  JSON.parse(raw_response)
81
119
  rescue JSON::ParserError => e
82
120
  return raw_response.body
121
+ ensure
122
+ payload.close if payload.is_a?(File)
83
123
  end
84
124
 
85
- def build_headers(customer_access_token: nil, idempotency_key: nil, extra_headers: nil, json:)
125
+ def build_headers(customer_access_token: nil, idempotency_key: nil, extra_headers: nil, json:, payload: nil)
86
126
  headers = {
87
127
  accept: :json,
88
128
  }
129
+ headers["Transfer-Encoding"] = "chunked" if payload.is_a?(Pathname)
89
130
  headers[:content_type] = :json if json
90
131
  headers["Authorization"] = "Bearer #{customer_access_token}" unless customer_access_token.nil?
91
132
  headers["Ibanity-Idempotency-Key"] = idempotency_key unless idempotency_key.nil?
@@ -95,5 +136,38 @@ module Ibanity
95
136
  headers.merge(extra_headers)
96
137
  end
97
138
  end
139
+
140
+ def log(tag, info)
141
+ unless info.is_a?(Hash)
142
+ puts "[DEBUG] #{tag}: #{info}"
143
+ return
144
+ end
145
+
146
+ info = JSON.parse(info.to_json)
147
+
148
+ if info.dig("headers", "Authorization")
149
+ info["headers"]["Authorization"] = "[filtered]"
150
+ end
151
+ info.delete("proxy")
152
+ info.delete("ssl_client_cert")
153
+ info.delete("ssl_client_key")
154
+ if info.dig("payload").is_a?(Hash) && info.dig("payload", "client_secret")
155
+ info["payload"]["client_secret"] = "[filtered]"
156
+ end
157
+
158
+ if info["body"]&.is_a?(String)
159
+ begin
160
+ info["body"] = JSON.parse(info["body"])
161
+ rescue => exception
162
+ info["body"] = Base64.strict_encode64(info["body"])
163
+ end
164
+ end
165
+
166
+ begin
167
+ puts "[DEBUG] #{tag}: #{info.to_json}"
168
+ rescue => e
169
+ puts "[DEBUG] #{tag}: #{info}"
170
+ end
171
+ end
98
172
  end
99
173
  end
data/lib/ibanity/error.rb CHANGED
@@ -22,6 +22,8 @@ module Ibanity
22
22
  formatted_errors.join("\n")
23
23
  elsif @errors.is_a?(Hash)
24
24
  "* #{@errors["error"]}: #{@errors["error_description"]}\n * Error hint: #{@errors["error_hint"]}\n * ibanity_request_id: #{@ibanity_request_id}"
25
+ elsif @errors.is_a?(String)
26
+ @errors
25
27
  else
26
28
  super
27
29
  end
@@ -1,4 +1,5 @@
1
1
  require "base64"
2
+ require "pathname"
2
3
 
3
4
  module Ibanity
4
5
  class HttpSignature
@@ -29,16 +30,38 @@ module Ibanity
29
30
  }
30
31
  end
31
32
 
32
- private
33
-
34
33
  def payload_digest
35
- digest = OpenSSL::Digest::SHA512.new
36
- string_payload = @payload.nil? ? "" : @payload
37
- digest.update(string_payload)
34
+ @payload_digest ||= compute_digest
35
+ end
36
+
37
+ def compute_digest
38
+ case @payload
39
+ when NilClass
40
+ digest = compute_digest_string("")
41
+ when String
42
+ digest = compute_digest_string(@payload)
43
+ when File
44
+ digest = compute_digest_file(@payload)
45
+ end
38
46
  base64 = Base64.urlsafe_encode64(digest.digest)
39
47
  "SHA-512=#{base64}"
40
48
  end
41
49
 
50
+ def compute_digest_string(str)
51
+ digest = OpenSSL::Digest::SHA512.new
52
+ digest.update(str)
53
+ end
54
+
55
+ def compute_digest_file(pathname)
56
+ digest = OpenSSL::Digest::SHA512.new
57
+ File.open(pathname, 'rb') do |f|
58
+ while buffer = f.read(256_000)
59
+ digest << buffer
60
+ end
61
+ end
62
+ digest
63
+ end
64
+
42
65
  def headers_to_sign
43
66
  result = ["(request-target)", "host", "digest", "(created)"]
44
67
  result << "authorization" unless @headers["Authorization"].nil?
@@ -1,3 +1,3 @@
1
1
  module Ibanity
2
- VERSION = "1.7.0"
2
+ VERSION = "1.11.0"
3
3
  end
@@ -0,0 +1,94 @@
1
+ module Ibanity
2
+ module Webhook
3
+ DEFAULT_TOLERANCE = 30
4
+ SIGNING_ALGORITHM = "RS512"
5
+
6
+ # Initializes an Ibanity Webhooks event object from a JSON payload.
7
+ #
8
+ # This may raise JSON::ParserError if the payload is not valid JSON, or
9
+ # Ibanity::Error if the signature verification fails.
10
+ def self.construct_event!(payload, signature_header, tolerance: DEFAULT_TOLERANCE)
11
+ Signature.verify!(payload, signature_header, tolerance)
12
+
13
+ raw_item = JSON.parse(payload)
14
+ klass = raw_item["data"]["type"].split(".").map{|klass| klass.sub(/\S/, &:upcase)}.join("::")
15
+ Ibanity::Webhooks.const_get(klass).new(raw_item["data"])
16
+ end
17
+
18
+ module Signature
19
+ # Verifies the signature header for a given payload.
20
+ #
21
+ # Raises an Ibanity::Error in the following cases:
22
+ # - the header does not match the expected format
23
+ # - the digest does not match the payload
24
+ # - the issued at or expiration timestamp is not within the tolerance
25
+ # - the audience or issuer does not match the application config
26
+ #
27
+ # Returns true otherwise
28
+ def self.verify!(payload, signature_header, tolerance)
29
+ begin
30
+ key_details = JOSE::JWT.peek_protected(signature_header).to_hash
31
+ raise unless key_details["alg"] == SIGNING_ALGORITHM && key_details["kid"]
32
+ rescue
33
+ raise Ibanity::Error.new("Key details could not be parsed from the header", nil)
34
+ end
35
+
36
+ key = Ibanity.webhook_keys.find { |key| key.kid == key_details["kid"] }
37
+
38
+ if key.nil?
39
+ raise Ibanity::Error.new("The key id from the header didn't match an available signing key", nil)
40
+ end
41
+ signer = JOSE::JWK.from(key.to_h {|key, value| [key.to_s, value] })
42
+ verified, claims_string, _jws = JOSE::JWT.verify_strict(signer, [SIGNING_ALGORITHM], signature_header)
43
+
44
+ raise Ibanity::Error.new("The signature verification failed", nil) unless verified
45
+
46
+ jwt = JOSE::JWT.from(claims_string)
47
+
48
+ validate_digest!(jwt, payload)
49
+ validate_issued_at!(jwt, tolerance)
50
+ validate_expiration!(jwt, tolerance)
51
+ validate_issuer!(jwt)
52
+ validate_audience!(jwt)
53
+
54
+ true
55
+ end
56
+
57
+ private
58
+
59
+ def self.validate_digest!(jwt, payload)
60
+ unless Digest::SHA512.base64digest(payload) == jwt.fields["digest"]
61
+ raise_invalid_signature_error!("digest")
62
+ end
63
+ end
64
+
65
+ def self.validate_issued_at!(jwt, tolerance)
66
+ unless jwt.fields["iat"] <= Time.now.to_i + tolerance
67
+ raise_invalid_signature_error!("iat")
68
+ end
69
+ end
70
+
71
+ def self.validate_expiration!(jwt, tolerance)
72
+ unless jwt.fields["exp"] >= Time.now.to_i - tolerance
73
+ raise_invalid_signature_error!("exp")
74
+ end
75
+ end
76
+
77
+ def self.validate_issuer!(jwt)
78
+ unless jwt.fields["iss"] == Ibanity.client.base_uri
79
+ raise_invalid_signature_error!("iss")
80
+ end
81
+ end
82
+
83
+ def self.validate_audience!(jwt)
84
+ unless jwt.fields["aud"] == Ibanity.client.application_id
85
+ raise_invalid_signature_error!("aud")
86
+ end
87
+ end
88
+
89
+ def self.raise_invalid_signature_error!(field)
90
+ raise Ibanity::Error.new("The signature #{field} is invalid", nil)
91
+ end
92
+ end
93
+ end
94
+ end
data/lib/ibanity.rb CHANGED
@@ -4,6 +4,7 @@ require "uri"
4
4
  require "rest_client"
5
5
  require "json"
6
6
  require "securerandom"
7
+ require "jose"
7
8
 
8
9
  require_relative "ibanity/util"
9
10
  require_relative "ibanity/error"
@@ -11,6 +12,8 @@ require_relative "ibanity/collection"
11
12
  require_relative "ibanity/client"
12
13
  require_relative "ibanity/http_signature"
13
14
  require_relative "ibanity/api/base_resource"
15
+ require_relative "ibanity/api/flat_resource"
16
+ require_relative "ibanity/webhook"
14
17
  require_relative "ibanity/api/xs2a/account"
15
18
  require_relative "ibanity/api/xs2a/transaction"
16
19
  require_relative "ibanity/api/xs2a/holding"
@@ -33,6 +36,7 @@ require_relative "ibanity/api/isabel_connect/intraday_transaction"
33
36
  require_relative "ibanity/api/isabel_connect/account_report"
34
37
  require_relative "ibanity/api/isabel_connect/access_token"
35
38
  require_relative "ibanity/api/isabel_connect/refresh_token"
39
+ require_relative "ibanity/api/isabel_connect/token"
36
40
  require_relative "ibanity/api/isabel_connect/bulk_payment_initiation_request"
37
41
  require_relative "ibanity/api/sandbox/financial_institution_account"
38
42
  require_relative "ibanity/api/sandbox/financial_institution_transaction"
@@ -46,18 +50,24 @@ require_relative "ibanity/api/ponto_connect/synchronization"
46
50
  require_relative "ibanity/api/consent/consent"
47
51
  require_relative "ibanity/api/consent/processing_operation"
48
52
  require_relative "ibanity/api/ponto_connect/payment"
53
+ require_relative "ibanity/api/ponto_connect/bulk_payment"
49
54
  require_relative "ibanity/api/ponto_connect/user_info"
50
55
  require_relative "ibanity/api/ponto_connect/usage"
51
56
  require_relative "ibanity/api/ponto_connect/integration"
52
57
  require_relative "ibanity/api/ponto_connect/sandbox/financial_institution_account"
53
58
  require_relative "ibanity/api/ponto_connect/sandbox/financial_institution_transaction"
54
59
  require_relative "ibanity/api/ponto_connect/onboarding_details"
60
+ require_relative "ibanity/api/ponto_connect/reauthorization_request"
61
+ require_relative "ibanity/api/ponto_connect/payment_activation_request"
62
+ require_relative "ibanity/api/webhooks/key"
63
+ require_relative "ibanity/api/webhooks/xs2a"
64
+ require_relative "ibanity/api/webhooks/ponto_connect"
55
65
 
56
66
  module Ibanity
57
67
  class << self
58
68
  def client
59
69
  options = configuration.to_h.delete_if { |_, v| v.nil? }
60
- @client ||= Ibanity::Client.new(options)
70
+ @client ||= Ibanity::Client.new(**options)
61
71
  end
62
72
 
63
73
  def configure
@@ -66,6 +76,7 @@ module Ibanity
66
76
  @isabel_connect_api_schema = nil
67
77
  @consent_api_schema = nil
68
78
  @ponto_connect_api_schema = nil
79
+ @webhooks_api_schema = nil
69
80
  @sandbox_api_schema = nil
70
81
  @configuration = nil
71
82
  yield configuration
@@ -86,8 +97,10 @@ module Ibanity
86
97
  :ponto_connect_client_secret,
87
98
  :api_scheme,
88
99
  :api_host,
89
- :api_port,
90
- :ssl_ca_file
100
+ :ssl_ca_file,
101
+ :application_id,
102
+ :debug_http_requests,
103
+ :timeout
91
104
  ).new
92
105
  end
93
106
 
@@ -111,6 +124,14 @@ module Ibanity
111
124
  @consent_api_schema ||= client.get(uri: "#{client.base_uri}/consent")["links"]
112
125
  end
113
126
 
127
+ def webhooks_api_schema
128
+ @webhooks_api_schema ||= client.get(uri: "#{client.base_uri}/webhooks")["links"]
129
+ end
130
+
131
+ def webhook_keys
132
+ @webhook_keys ||= Ibanity::Webhooks::Key.list
133
+ end
134
+
114
135
  def respond_to_missing?(method_name, include_private = false)
115
136
  client.respond_to?(method_name, include_private)
116
137
  end
@@ -0,0 +1,42 @@
1
+ require "ibanity"
2
+
3
+ class Ibanity::Xs2a::Car < Ibanity::BaseResource; end
4
+ class Ibanity::Xs2a::Manufacturer < Ibanity::BaseResource; end
5
+
6
+ RSpec.describe Ibanity::BaseResource do
7
+ describe "#relationship_klass" do
8
+ context "when 'data' attribute is present" do
9
+ it "retrieves the resource name from the 'type' attribute if it is present" do
10
+ car = Ibanity::Xs2a::Car.new(Fixture.load_json("relationships/data_with_type.json"))
11
+
12
+ expect(car).to respond_to(:maker)
13
+ end
14
+
15
+ it "falls back to the element name otherwise" do
16
+ car = Ibanity::Xs2a::Car.new(Fixture.load_json("relationships/data_without_type.json"))
17
+
18
+ expect(car).to respond_to(:manufacturer)
19
+ end
20
+ end
21
+
22
+ context "when the 'links' attribute is present" do
23
+ it "retrieves the resource name from the 'type' attribute within the 'links' attribute" do
24
+ car = Ibanity::Xs2a::Car.new(Fixture.load_json("relationships/meta_with_type.json"))
25
+
26
+ expect(car).to respond_to(:manufacturer)
27
+ end
28
+ end
29
+
30
+ context "when there's no 'links/related' element" do
31
+ let(:car) { Ibanity::Xs2a::Car.new(Fixture.load_json("relationships/no_links_related.json")) }
32
+
33
+ it "sets up a '<relationship_key>_id' property when there is a 'data/id' element" do
34
+ expect(car.manufacturer_id).to eq("6680437c")
35
+ end
36
+
37
+ it "discards the relationship" do
38
+ expect(car).not_to respond_to(:manufacturer)
39
+ end
40
+ end
41
+ end
42
+ end
data/spec/spec_helper.rb CHANGED
@@ -12,10 +12,16 @@
12
12
  # the additional setup, and require it from the spec files that actually need
13
13
  # it.
14
14
  #
15
+
16
+ Pathname.glob(Pathname.pwd().join("spec", "support", "**/*.rb")).each do |f|
17
+ require f
18
+ end
19
+
15
20
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
21
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
17
22
 
18
23
  RSpec.configure do |config|
24
+ config.include(Fixture)
19
25
  # rspec-expectations config goes here. You can use an alternate
20
26
  # assertion/expectation library such as wrong or the stdlib/minitest
21
27
  # assertions if you prefer.
@@ -0,0 +1,8 @@
1
+ require "json"
2
+
3
+ module Fixture
4
+ def self.load_json(filename)
5
+ path = Pathname([File.dirname(__FILE__ ), "fixtures", "json", filename].join("/"))
6
+ JSON.parse(File.read(path))
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ {
2
+ "attributes": {
3
+ "color": "blue"
4
+ },
5
+ "id": "62ebd4687e",
6
+ "links": {
7
+ "self": "https://www.cardb.com/models/62ebd4687e"
8
+ },
9
+ "relationships": {
10
+ "maker": {
11
+ "data": {
12
+ "id": "c4ebf0f7",
13
+ "type": "manufacturer"
14
+ },
15
+ "links": {
16
+ "related": "https://www.cardb.com/manufacturers/c4ebf0f7"
17
+ }
18
+ }
19
+ },
20
+ "type": "car"
21
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "attributes": {
3
+ "color": "blue"
4
+ },
5
+ "id": "62ebd4687e",
6
+ "links": {
7
+ "self": "https://www.cardb.com/models/62ebd4687e"
8
+ },
9
+ "relationships": {
10
+ "manufacturer": {
11
+ "data": {
12
+ "id": "c4ebf0f7"
13
+ },
14
+ "links": {
15
+ "related": "https://www.cardb.com/manufacturers/c4ebf0f7"
16
+ }
17
+ }
18
+ },
19
+ "type": "car"
20
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "attributes": {
3
+ "color": "blue"
4
+ },
5
+ "id": "62ebd4687e",
6
+ "links": {
7
+ "self": "https://www.cardb.com/models/62ebd4687e"
8
+ },
9
+ "relationships": {
10
+ "manufacturer": {
11
+ "links": {
12
+ "related": "https://www.cardb.com/manufacturers/c4ebf0f7"
13
+ },
14
+ "meta": {
15
+ "type": "manufacturer"
16
+ }
17
+ }
18
+ },
19
+ "type": "car"
20
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "62ebd4687e",
3
+ "attributes": {
4
+ "color": "blue"
5
+ },
6
+ "relationships": {
7
+ "manufacturer": {
8
+ "data": {
9
+ "type": "manufacturer",
10
+ "id": "6680437c"
11
+ }
12
+ }
13
+ },
14
+ "type": "car"
15
+ }
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: 1.7.0
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ibanity
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-05 00:00:00.000000000 Z
11
+ date: 2022-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.8.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: jose
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.1.3
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rspec
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -60,6 +74,7 @@ files:
60
74
  - lib/ibanity/api/base_resource.rb
61
75
  - lib/ibanity/api/consent/consent.rb
62
76
  - lib/ibanity/api/consent/processing_operation.rb
77
+ - lib/ibanity/api/flat_resource.rb
63
78
  - lib/ibanity/api/isabel_connect/access_token.rb
64
79
  - lib/ibanity/api/isabel_connect/account.rb
65
80
  - lib/ibanity/api/isabel_connect/account_report.rb
@@ -67,13 +82,17 @@ files:
67
82
  - lib/ibanity/api/isabel_connect/bulk_payment_initiation_request.rb
68
83
  - lib/ibanity/api/isabel_connect/intraday_transaction.rb
69
84
  - lib/ibanity/api/isabel_connect/refresh_token.rb
85
+ - lib/ibanity/api/isabel_connect/token.rb
70
86
  - lib/ibanity/api/isabel_connect/transaction.rb
71
87
  - lib/ibanity/api/o_auth_resource.rb
72
88
  - lib/ibanity/api/ponto_connect/account.rb
89
+ - lib/ibanity/api/ponto_connect/bulk_payment.rb
73
90
  - lib/ibanity/api/ponto_connect/financial_institution.rb
74
91
  - lib/ibanity/api/ponto_connect/integration.rb
75
92
  - lib/ibanity/api/ponto_connect/onboarding_details.rb
76
93
  - lib/ibanity/api/ponto_connect/payment.rb
94
+ - lib/ibanity/api/ponto_connect/payment_activation_request.rb
95
+ - lib/ibanity/api/ponto_connect/reauthorization_request.rb
77
96
  - lib/ibanity/api/ponto_connect/sandbox/financial_institution_account.rb
78
97
  - lib/ibanity/api/ponto_connect/sandbox/financial_institution_transaction.rb
79
98
  - lib/ibanity/api/ponto_connect/synchronization.rb
@@ -85,6 +104,9 @@ files:
85
104
  - lib/ibanity/api/sandbox/financial_institution_holding.rb
86
105
  - lib/ibanity/api/sandbox/financial_institution_transaction.rb
87
106
  - lib/ibanity/api/sandbox/financial_institution_user.rb
107
+ - lib/ibanity/api/webhooks/key.rb
108
+ - lib/ibanity/api/webhooks/ponto_connect.rb
109
+ - lib/ibanity/api/webhooks/xs2a.rb
88
110
  - lib/ibanity/api/xs2a/account.rb
89
111
  - lib/ibanity/api/xs2a/account_information_access_request.rb
90
112
  - lib/ibanity/api/xs2a/account_information_access_request_authorization.rb
@@ -105,10 +127,17 @@ files:
105
127
  - lib/ibanity/http_signature.rb
106
128
  - lib/ibanity/util.rb
107
129
  - lib/ibanity/version.rb
130
+ - lib/ibanity/webhook.rb
131
+ - spec/lib/ibanity/base_resource_spec.rb
108
132
  - spec/lib/ibanity/http_signature_spec.rb
109
133
  - spec/lib/ibanity/util_spec.rb
110
134
  - spec/spec_helper.rb
111
135
  - spec/support/crypto_helper.rb
136
+ - spec/support/fixture.rb
137
+ - spec/support/fixtures/json/relationships/data_with_type.json
138
+ - spec/support/fixtures/json/relationships/data_without_type.json
139
+ - spec/support/fixtures/json/relationships/meta_with_type.json
140
+ - spec/support/fixtures/json/relationships/no_links_related.json
112
141
  - spec/support/fixtures/signature/test-certificate.pem
113
142
  - spec/support/fixtures/signature/test-private_key.pem
114
143
  - spec/support/fixtures/signature/test-public_key.pem
@@ -131,15 +160,21 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
160
  - !ruby/object:Gem::Version
132
161
  version: '0'
133
162
  requirements: []
134
- rubygems_version: 3.0.3
163
+ rubygems_version: 3.0.3.1
135
164
  signing_key:
136
165
  specification_version: 4
137
166
  summary: Ibanity Ruby Client
138
167
  test_files:
168
+ - spec/lib/ibanity/base_resource_spec.rb
139
169
  - spec/lib/ibanity/http_signature_spec.rb
140
170
  - spec/lib/ibanity/util_spec.rb
141
171
  - spec/spec_helper.rb
142
172
  - spec/support/crypto_helper.rb
173
+ - spec/support/fixture.rb
174
+ - spec/support/fixtures/json/relationships/data_with_type.json
175
+ - spec/support/fixtures/json/relationships/data_without_type.json
176
+ - spec/support/fixtures/json/relationships/meta_with_type.json
177
+ - spec/support/fixtures/json/relationships/no_links_related.json
143
178
  - spec/support/fixtures/signature/test-certificate.pem
144
179
  - spec/support/fixtures/signature/test-private_key.pem
145
180
  - spec/support/fixtures/signature/test-public_key.pem