bunq-client 0.7.2 → 1.0.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 +4 -4
- data/.github/workflows/rspec.yml +40 -0
- data/.rubocop.yml +212 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +4 -0
- data/Gemfile +2 -0
- data/README.md +2 -0
- data/Rakefile +7 -3
- data/bunq-client.gemspec +22 -20
- data/lib/bunq/attachment.rb +15 -0
- data/lib/bunq/attachment_public.rb +13 -0
- data/lib/bunq/attachment_public_content.rb +4 -2
- data/lib/bunq/attachment_publics.rb +20 -0
- data/lib/bunq/attachments.rb +20 -0
- data/lib/bunq/avatar.rb +15 -0
- data/lib/bunq/avatars.rb +15 -0
- data/lib/bunq/bunq.rb +2 -0
- data/lib/bunq/bunqme_tab.rb +17 -0
- data/lib/bunq/bunqme_tabs.rb +21 -0
- data/lib/bunq/card.rb +2 -0
- data/lib/bunq/cards.rb +3 -1
- data/lib/bunq/certificate_pinned.rb +10 -6
- data/lib/bunq/client.rb +74 -51
- data/lib/bunq/device_servers.rb +5 -4
- data/lib/bunq/draft_share_invite_bank.rb +2 -0
- data/lib/bunq/draft_share_invite_banks.rb +3 -1
- data/lib/bunq/encryptor.rb +6 -7
- data/lib/bunq/errors.rb +9 -2
- data/lib/bunq/header.rb +20 -0
- data/lib/bunq/installation.rb +2 -0
- data/lib/bunq/installations.rb +4 -2
- data/lib/bunq/monetary_account.rb +17 -0
- data/lib/bunq/monetary_account_bank.rb +17 -0
- data/lib/bunq/monetary_account_banks.rb +21 -0
- data/lib/bunq/monetary_accounts.rb +3 -1
- data/lib/bunq/notification_filter_url.rb +4 -2
- data/lib/bunq/paginated.rb +14 -3
- data/lib/bunq/payment.rb +2 -0
- data/lib/bunq/payments.rb +3 -1
- data/lib/bunq/qr_code_content.rb +5 -3
- data/lib/bunq/resource.rb +25 -11
- data/lib/bunq/session_servers.rb +5 -2
- data/lib/bunq/signature.rb +9 -7
- data/lib/bunq/user.rb +17 -0
- data/lib/bunq/user_company.rb +2 -0
- data/lib/bunq/user_person.rb +2 -0
- data/lib/bunq/users.rb +17 -0
- data/lib/bunq/version.rb +3 -1
- metadata +53 -20
- data/.travis.yml +0 -5
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module Bunq
|
6
|
+
class Attachments
|
7
|
+
def initialize(parent_resource)
|
8
|
+
@resource = parent_resource.append('/attachment')
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(binary_payload, description, mime_type)
|
12
|
+
custom_headers = {
|
13
|
+
Bunq::Header::CONTENT_TYPE => mime_type,
|
14
|
+
Bunq::Header::ATTACHMENT_DESCRIPTION => description,
|
15
|
+
}
|
16
|
+
payload = Base64.decode64(binary_payload)
|
17
|
+
@resource.with_session { @resource.post(payload, custom_headers: custom_headers) }['Response']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/bunq/avatar.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'resource'
|
4
|
+
|
5
|
+
module Bunq
|
6
|
+
class Avatar
|
7
|
+
def initialize(client, id)
|
8
|
+
@resource = Bunq::Resource.new(client, "/v1/avatar/#{id}")
|
9
|
+
end
|
10
|
+
|
11
|
+
def show
|
12
|
+
@resource.with_session { @resource.get }['Response']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/bunq/avatars.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'resource'
|
4
|
+
|
5
|
+
module Bunq
|
6
|
+
class Avatars
|
7
|
+
def initialize(client)
|
8
|
+
@resource = Bunq::Resource.new(client, '/v1/avatar')
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(attachment_public_uuid)
|
12
|
+
@resource.with_session { @resource.post({attachment_public_uuid: attachment_public_uuid}) }['Response']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/bunq/bunq.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bunq
|
4
|
+
class BunqmeTab
|
5
|
+
def initialize(parent_resource, id)
|
6
|
+
@resource = parent_resource.append("/bunqme-tab/#{id}")
|
7
|
+
end
|
8
|
+
|
9
|
+
def show
|
10
|
+
@resource.with_session { @resource.get }['Response']
|
11
|
+
end
|
12
|
+
|
13
|
+
def update(attributes)
|
14
|
+
@resource.with_session { @resource.put(attributes) }['Response']
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'paginated'
|
4
|
+
|
5
|
+
module Bunq
|
6
|
+
class BunqmeTabs
|
7
|
+
def initialize(parent_resource)
|
8
|
+
@resource = parent_resource.append('/bunqme-tab')
|
9
|
+
end
|
10
|
+
|
11
|
+
def index(count: 200, older_id: nil, newer_id: nil)
|
12
|
+
Bunq::Paginated
|
13
|
+
.new(@resource)
|
14
|
+
.paginate(count: count, older_id: older_id, newer_id: newer_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(attributes)
|
18
|
+
@resource.with_session { @resource.post(attributes) }['Response']
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/bunq/card.rb
CHANGED
data/lib/bunq/cards.rb
CHANGED
@@ -1,20 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Bunq
|
2
4
|
##
|
3
5
|
# https://doc.bunq.com/api/1/call/certificate-pinned
|
4
6
|
class CertificatePinned
|
5
7
|
def initialize(parent_resource)
|
6
|
-
@resource = parent_resource.append(
|
8
|
+
@resource = parent_resource.append('/certificate-pinned')
|
7
9
|
end
|
8
10
|
|
9
11
|
##
|
10
12
|
# https://doc.bunq.com/api/1/call/certificate-pinned/method/post
|
11
13
|
def create(pem_certificate)
|
12
14
|
@resource.with_session do
|
13
|
-
@resource.post(
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
@resource.post(
|
16
|
+
{
|
17
|
+
certificate_chain: [
|
18
|
+
{certificate: pem_certificate},
|
19
|
+
],
|
20
|
+
},
|
21
|
+
)
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
data/lib/bunq/client.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'openssl'
|
2
4
|
require 'base64'
|
3
5
|
require 'thread_safe'
|
4
6
|
|
5
7
|
require_relative './version'
|
8
|
+
require_relative './header'
|
6
9
|
require_relative './resource'
|
7
10
|
|
11
|
+
require_relative './attachment_publics'
|
12
|
+
require_relative './attachment_public'
|
13
|
+
require_relative './avatars'
|
14
|
+
require_relative './avatar'
|
8
15
|
require_relative './installations'
|
9
16
|
require_relative './installation'
|
10
17
|
require_relative './device_servers'
|
@@ -18,7 +25,7 @@ require_relative './monetary_accounts'
|
|
18
25
|
require_relative './payment'
|
19
26
|
require_relative './payments'
|
20
27
|
require_relative './signature'
|
21
|
-
require_relative './attachment_public_content
|
28
|
+
require_relative './attachment_public_content'
|
22
29
|
|
23
30
|
##
|
24
31
|
# Usage
|
@@ -53,7 +60,8 @@ module Bunq
|
|
53
60
|
# Returns a new instance of +Client+ with the current +configuration+.
|
54
61
|
#
|
55
62
|
def client
|
56
|
-
fail
|
63
|
+
fail 'No configuration! Call Bunq.configure first.' unless configuration
|
64
|
+
|
57
65
|
Client.new(configuration.dup)
|
58
66
|
end
|
59
67
|
end
|
@@ -112,40 +120,40 @@ module Bunq
|
|
112
120
|
|
113
121
|
# Base url for the bunq api. Defaults to +PRODUCTION_BASE_URL+
|
114
122
|
attr_accessor :base_url,
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
123
|
+
# Flag to set to connect to sandbox. Defaults to +false+.
|
124
|
+
# If set to +true+ you must also specify +sandbox_user+
|
125
|
+
# and +sandbox_password+
|
126
|
+
:sandbox,
|
127
|
+
# The username for connecting to the sandbox
|
128
|
+
:sandbox_user,
|
129
|
+
# The password for connecting to the sandbox
|
130
|
+
:sandbox_password,
|
131
|
+
# Your installation token obtained from bunq
|
132
|
+
:installation_token,
|
133
|
+
# Your api key obtained from bunq
|
134
|
+
:api_key,
|
135
|
+
# Your language. Defaults to +DEFAULT_LANGUAGE+
|
136
|
+
:language,
|
137
|
+
# Your region. Defaults to +DEFAULT_REGION+
|
138
|
+
:region,
|
139
|
+
# Your geolocation. Defaults to +DEFAULT_GEOLOCATION+
|
140
|
+
:geolocation,
|
141
|
+
# Arbitrary user agent to connect to bunq. Defaults to +DEFAULT_USER_AGENT+
|
142
|
+
:user_agent,
|
143
|
+
# Flag to set when you want to disable the signature
|
144
|
+
# retrieved from bunq. Mainly useful for testing.
|
145
|
+
# Defaults to +false+
|
146
|
+
:disable_response_signature_verification,
|
147
|
+
# The private key for signing the request
|
148
|
+
:private_key,
|
149
|
+
# The public key of this installation for verifying the response
|
150
|
+
:server_public_key,
|
151
|
+
# Timeout in seconds to wait for bunq api. Defaults to +DEFAULT_TIMEOUT+
|
152
|
+
:timeout,
|
153
|
+
# Cache to retrieve current session from. Defaults to +DEFAULT_SESSION_CACHE+,
|
154
|
+
# which will create a new session per `Bunq.client` instance.
|
155
|
+
# See +ThreadSafeSessionCache+ for more advanced use.
|
156
|
+
:session_cache
|
149
157
|
|
150
158
|
def initialize
|
151
159
|
@sandbox = false
|
@@ -165,14 +173,33 @@ module Bunq
|
|
165
173
|
#
|
166
174
|
# An instance of a +Client+ can be obtained via +Bunq.client+
|
167
175
|
class Client
|
176
|
+
APPLICATION_JSON = 'application/json'
|
177
|
+
|
168
178
|
attr_accessor :current_session
|
169
179
|
attr_reader :configuration
|
170
180
|
|
171
181
|
def initialize(configuration)
|
172
|
-
fail ArgumentError
|
182
|
+
fail ArgumentError, 'configuration is required' unless configuration
|
183
|
+
|
173
184
|
@configuration = configuration
|
174
185
|
end
|
175
186
|
|
187
|
+
def attachment_publics
|
188
|
+
Bunq::AttachmentPublics.new(self)
|
189
|
+
end
|
190
|
+
|
191
|
+
def attachment_public(id)
|
192
|
+
Bunq::AttachmentPublic.new(self, id)
|
193
|
+
end
|
194
|
+
|
195
|
+
def avatars
|
196
|
+
Bunq::Avatars.new(self)
|
197
|
+
end
|
198
|
+
|
199
|
+
def avatar(id)
|
200
|
+
Bunq::Avatar.new(self, id)
|
201
|
+
end
|
202
|
+
|
176
203
|
def installations
|
177
204
|
Bunq::Installations.new(self)
|
178
205
|
end
|
@@ -226,7 +253,7 @@ module Bunq
|
|
226
253
|
end
|
227
254
|
|
228
255
|
def ensure_session!
|
229
|
-
@current_session ||= configuration.session_cache.get { create_session }
|
256
|
+
@current_session ||= configuration.session_cache.get { create_session } # rubocop:disable Naming/MemoizedInstanceVariableName
|
230
257
|
end
|
231
258
|
|
232
259
|
def create_session
|
@@ -254,21 +281,17 @@ module Bunq
|
|
254
281
|
|
255
282
|
def headers
|
256
283
|
{
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
284
|
+
Bunq::Header::ACCEPT => APPLICATION_JSON,
|
285
|
+
Bunq::Header::CACHE_CONTROL => 'no-cache',
|
286
|
+
Bunq::Header::CONTENT_TYPE => APPLICATION_JSON,
|
287
|
+
Bunq::Header::USER_AGENT => configuration.user_agent,
|
288
|
+
Bunq::Header::LANGUAGE => configuration.language,
|
289
|
+
Bunq::Header::GEOLOCATION => configuration.geolocation,
|
290
|
+
Bunq::Header::REGION => configuration.region,
|
264
291
|
}.tap do |h|
|
265
|
-
if configuration.installation_token
|
266
|
-
h[:'X-Bunq-Client-Authentication'] = configuration.installation_token
|
267
|
-
end
|
292
|
+
h[Bunq::Header::CLIENT_AUTH] = configuration.installation_token if configuration.installation_token
|
268
293
|
|
269
|
-
if current_session
|
270
|
-
h[:'X-Bunq-Client-Authentication'] = current_session[1]['Token']['token']
|
271
|
-
end
|
294
|
+
h[Bunq::Header::CLIENT_AUTH] = current_session[1]['Token']['token'] if current_session
|
272
295
|
end
|
273
296
|
end
|
274
297
|
|
data/lib/bunq/device_servers.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Bunq
|
2
4
|
##
|
3
5
|
# See https://doc.bunq.com/api/1/call/device-server
|
4
6
|
class DeviceServers
|
5
|
-
|
6
7
|
##
|
7
8
|
# +client+ an instance of +Bunq::Client+
|
8
9
|
#
|
9
10
|
def initialize(client)
|
10
|
-
@resource = Bunq::Resource.new(client,
|
11
|
+
@resource = Bunq::Resource.new(client, '/v1/device-server')
|
11
12
|
@client = client
|
12
13
|
end
|
13
14
|
|
@@ -20,10 +21,10 @@ module Bunq
|
|
20
21
|
# @param description [String] The description of this device server.
|
21
22
|
# @param permitted_ips [Array|nil] Array of permitted IP addresses.
|
22
23
|
def create(description, permitted_ips: nil)
|
23
|
-
fail ArgumentError
|
24
|
+
fail ArgumentError, 'description is required' unless description
|
24
25
|
fail 'Cannot create session, please add the api_key to your configuration' unless @client.configuration.api_key
|
25
26
|
|
26
|
-
params = {
|
27
|
+
params = {description: description, secret: @client.configuration.api_key}
|
27
28
|
params[:permitted_ips] = permitted_ips if permitted_ips
|
28
29
|
|
29
30
|
@resource.post(params)['Response']
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'qr_code_content'
|
2
4
|
|
3
5
|
module Bunq
|
4
6
|
class DraftShareInviteBanks
|
5
7
|
def initialize(parent_resource)
|
6
|
-
@resource = parent_resource.append(
|
8
|
+
@resource = parent_resource.append('/draft-share-invite-bank')
|
7
9
|
end
|
8
10
|
|
9
11
|
def create(invite)
|
data/lib/bunq/encryptor.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Bunq
|
2
4
|
class Encryptor
|
3
|
-
HEADER_CLIENT_ENCRYPTION_HMAC = 'X-Bunq-Client-Encryption-Hmac'
|
4
|
-
HEADER_CLIENT_ENCRYPTION_IV = 'X-Bunq-Client-Encryption-Iv'
|
5
|
-
HEADER_CLIENT_ENCRYPTION_KEY = 'X-Bunq-Client-Encryption-Key'
|
6
5
|
AES_ENCRYPTION_METHOD = 'aes-256-cbc'
|
7
6
|
HMAC_ALGORITHM = 'sha1'
|
8
7
|
|
9
8
|
def initialize(server_public_key)
|
10
|
-
fail ArgumentError
|
9
|
+
fail ArgumentError, 'server_public_key is mandatory' unless server_public_key
|
11
10
|
|
12
11
|
@server_public_key = OpenSSL::PKey::RSA.new(server_public_key)
|
13
12
|
end
|
@@ -17,13 +16,13 @@ module Bunq
|
|
17
16
|
|
18
17
|
iv, key, encrypted_body = encrypt_body(body)
|
19
18
|
|
20
|
-
headers[
|
19
|
+
headers[Bunq::Header::CLIENT_ENCRYPTION_IV] = Base64.strict_encode64(iv)
|
21
20
|
|
22
21
|
encrypted_key = server_public_key.public_encrypt(key)
|
23
|
-
headers[
|
22
|
+
headers[Bunq::Header::CLIENT_ENCRYPTION_KEY] = Base64.strict_encode64(encrypted_key)
|
24
23
|
|
25
24
|
digest = hmac(key, iv + encrypted_body)
|
26
|
-
headers[
|
25
|
+
headers[Bunq::Header::CLIENT_ENCRYPTION_HMAC] = Base64.strict_encode64(digest)
|
27
26
|
|
28
27
|
[encrypted_body, headers]
|
29
28
|
end
|
data/lib/bunq/errors.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Bunq
|
2
4
|
class ResponseError < StandardError
|
3
5
|
attr_reader :code
|
4
6
|
attr_reader :headers
|
5
7
|
attr_reader :body
|
6
8
|
|
7
|
-
def initialize(msg =
|
9
|
+
def initialize(msg = 'Response error', code: nil, headers: nil, body: nil)
|
8
10
|
@code = code
|
9
11
|
@headers = headers || {}
|
10
12
|
@body = body
|
@@ -14,7 +16,12 @@ module Bunq
|
|
14
16
|
# Returns the parsed body if it is a JSON document, nil otherwise.
|
15
17
|
# @param opts [Hash] Optional options that are passed to `JSON.parse`.
|
16
18
|
def parsed_body(opts = {})
|
17
|
-
|
19
|
+
if @body && @headers['content-type'] && @headers['content-type'].include?('application/json')
|
20
|
+
JSON.parse(
|
21
|
+
@body,
|
22
|
+
opts,
|
23
|
+
)
|
24
|
+
end
|
18
25
|
end
|
19
26
|
|
20
27
|
# Returns an array of errors returned from the API, or nil if no errors are returned.
|