gocardless 1.11.1 → 1.11.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/lib/gocardless/client.rb +1 -1
- data/lib/gocardless/utils.rb +20 -1
- data/lib/gocardless/version.rb +1 -1
- data/spec/client_spec.rb +21 -13
- data/spec/page_spec.rb +2 -2
- data/spec/resource_spec.rb +10 -10
- data/spec/spec_helper.rb +2 -2
- data/spec/utils_spec.rb +10 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 417cec8542edd246281e1e82b45294ad06d09a5e
|
4
|
+
data.tar.gz: 2dae626c784514a1b722dbb348bd782e954f7c46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d47705fcf702d7fb7ed80a1e847b7953c4b235f6bb78d16961978c97166eaa9c9b1d790dde027e3a2cac7109170e5b2063e1fac1a4588a576aeb143314a68795
|
7
|
+
data.tar.gz: b8c4cc2cc8ad7aebf8586a8f9b901e160116b03039c1c820b5c3bdab1848bddd233e061c07ded755d63f67f5df2ae096dad29169f2c1ad9ffc221ab8932eccf2
|
data/CHANGELOG.md
CHANGED
data/lib/gocardless/client.rb
CHANGED
@@ -418,7 +418,7 @@ module GoCardless
|
|
418
418
|
def signature_valid?(params)
|
419
419
|
params = params.clone
|
420
420
|
signature = params.delete(:signature)
|
421
|
-
sign_params(params)[:signature]
|
421
|
+
Utils.secure_compare(sign_params(params)[:signature], signature)
|
422
422
|
end
|
423
423
|
|
424
424
|
# Generate a random base64-encoded string
|
data/lib/gocardless/utils.rb
CHANGED
@@ -82,7 +82,7 @@ module GoCardless
|
|
82
82
|
end * '&'
|
83
83
|
end
|
84
84
|
|
85
|
-
# Given a Hash of parameters, normalize
|
85
|
+
# Given a Hash of parameters, normalize them (flatten and convert to a
|
86
86
|
# string), then generate the HMAC-SHA-256 signature using the provided key.
|
87
87
|
#
|
88
88
|
# @param [Hash] params the parameters to sign
|
@@ -94,6 +94,25 @@ module GoCardless
|
|
94
94
|
OpenSSL::HMAC.hexdigest(digest, key, msg)
|
95
95
|
end
|
96
96
|
|
97
|
+
# Given two strings, compare them in constant time (for the length of the
|
98
|
+
# string). This can avoid timing attacks when used to compare signed
|
99
|
+
# parameters.
|
100
|
+
# Borrowed from ActiveSupport::MessageVerifier.
|
101
|
+
# https://github.com/rails/rails/blob/master/activesupport/lib/active_support/message_verifier.rb
|
102
|
+
#
|
103
|
+
# @param [String] the first string to compare
|
104
|
+
# @param [String] this second string to compare
|
105
|
+
# @return [Boolean] the result of the comparison
|
106
|
+
def secure_compare(a, b)
|
107
|
+
return false unless a.bytesize == b.bytesize
|
108
|
+
|
109
|
+
l = a.unpack("C#{a.bytesize}")
|
110
|
+
|
111
|
+
res = 0
|
112
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
113
|
+
res == 0
|
114
|
+
end
|
115
|
+
|
97
116
|
# Format a Time object according to ISO 8601, and convert to UTC.
|
98
117
|
#
|
99
118
|
# @param [Time] time the time object to format
|
data/lib/gocardless/version.rb
CHANGED
data/spec/client_spec.rb
CHANGED
@@ -235,7 +235,9 @@ describe GoCardless::Client do
|
|
235
235
|
token = @client.instance_variable_get(:@access_token)
|
236
236
|
r = double
|
237
237
|
r.stub(:parsed)
|
238
|
-
token.should_receive(:get)
|
238
|
+
token.should_receive(:get) do |p, o|
|
239
|
+
expect(p).to satisfy { |v| v =~ %r|/api/v1/test| }
|
240
|
+
end.and_return(r)
|
239
241
|
@client.api_get('/test')
|
240
242
|
end
|
241
243
|
|
@@ -250,7 +252,9 @@ describe GoCardless::Client do
|
|
250
252
|
token = @client.instance_variable_get(:@access_token)
|
251
253
|
r = double
|
252
254
|
r.stub(:parsed)
|
253
|
-
token.should_receive(:post)
|
255
|
+
token.should_receive(:post) do |p,opts|
|
256
|
+
expect(opts[:body]).to eq('{"a":1}')
|
257
|
+
end.and_return(r)
|
254
258
|
@client.api_post('/test', {:a => 1})
|
255
259
|
end
|
256
260
|
|
@@ -265,7 +269,9 @@ describe GoCardless::Client do
|
|
265
269
|
token = @client.instance_variable_get(:@access_token)
|
266
270
|
r = double
|
267
271
|
r.stub(:parsed)
|
268
|
-
token.should_receive(:delete)
|
272
|
+
token.should_receive(:delete) do |p,opts|
|
273
|
+
expect(opts[:body]).to eq('{"a":1}')
|
274
|
+
end.and_return(r)
|
269
275
|
@client.api_delete('/test', {:a => 1})
|
270
276
|
end
|
271
277
|
|
@@ -283,7 +289,9 @@ describe GoCardless::Client do
|
|
283
289
|
|
284
290
|
token = @client.instance_variable_get(:@access_token)
|
285
291
|
merchant_url = '/api/v1/merchants/123'
|
286
|
-
token.should_receive(:get)
|
292
|
+
token.should_receive(:get) do |p,o|
|
293
|
+
expect(p).to eq(merchant_url)
|
294
|
+
end.and_return response
|
287
295
|
|
288
296
|
GoCardless::Merchant.stub(:new_with_client)
|
289
297
|
|
@@ -331,12 +339,12 @@ describe GoCardless::Client do
|
|
331
339
|
|
332
340
|
it "succeeds with a valid signature" do
|
333
341
|
params = @client.send(:sign_params, @params)
|
334
|
-
@client.send(:signature_valid?, params).should
|
342
|
+
@client.send(:signature_valid?, params).should be_truthy
|
335
343
|
end
|
336
344
|
|
337
345
|
it "fails with an invalid signature" do
|
338
346
|
params = {:signature => 'invalid'}.merge(@params)
|
339
|
-
@client.send(:signature_valid?, params).should
|
347
|
+
@client.send(:signature_valid?, params).should be_falsey
|
340
348
|
end
|
341
349
|
end
|
342
350
|
|
@@ -380,11 +388,11 @@ describe GoCardless::Client do
|
|
380
388
|
it "includes valid http basic credentials" do
|
381
389
|
GoCardless::Subscription.stub(:find_with_client)
|
382
390
|
auth = 'Basic YWJjOnh5eg=='
|
383
|
-
@client.should_receive(:request)
|
391
|
+
@client.should_receive(:request) do |type, path, opts|
|
384
392
|
opts.should include :headers
|
385
393
|
opts[:headers].should include 'Authorization'
|
386
394
|
opts[:headers]['Authorization'].should == auth
|
387
|
-
end
|
395
|
+
end.once
|
388
396
|
@client.confirm_resource(@client.send(:sign_params, @params))
|
389
397
|
end
|
390
398
|
|
@@ -438,12 +446,12 @@ describe GoCardless::Client do
|
|
438
446
|
|
439
447
|
it "and_return false when the signature is invalid" do
|
440
448
|
params = {:signature => 'xxx'}.merge(@params)
|
441
|
-
@client.response_params_valid?(params).should
|
449
|
+
@client.response_params_valid?(params).should be_falsey
|
442
450
|
end
|
443
451
|
|
444
452
|
it "and_return true when the signature is valid" do
|
445
453
|
params = @client.send(:sign_params, @params)
|
446
|
-
@client.response_params_valid?(params).should
|
454
|
+
@client.response_params_valid?(params).should be_truthy
|
447
455
|
end
|
448
456
|
end
|
449
457
|
|
@@ -501,7 +509,7 @@ describe GoCardless::Client do
|
|
501
509
|
|
502
510
|
it "should include a valid signature" do
|
503
511
|
params = get_params(@client.send(:new_limit_url, :subscription, :x => 1))
|
504
|
-
params.key?('signature').should
|
512
|
+
params.key?('signature').should be_truthy
|
505
513
|
sig = params.delete('signature')
|
506
514
|
sig.should == @client.send(:sign_params, params.clone)[:signature]
|
507
515
|
end
|
@@ -542,13 +550,13 @@ describe GoCardless::Client do
|
|
542
550
|
describe "#webhook_valid?" do
|
543
551
|
it "and_return false when the webhook signature is invalid" do
|
544
552
|
@client.webhook_valid?({:some => 'stuff', :signature => 'invalid'}).
|
545
|
-
should
|
553
|
+
should be_falsey
|
546
554
|
end
|
547
555
|
|
548
556
|
it "and_return true when the webhook signature is valid" do
|
549
557
|
valid_signature = '175e814f0f64e5e86d41fb8fe06a857cedda715a96d3dc3d885e6d97dbeb7e49'
|
550
558
|
@client.webhook_valid?({:some => 'stuff', :signature => valid_signature}).
|
551
|
-
should
|
559
|
+
should be_truthy
|
552
560
|
end
|
553
561
|
end
|
554
562
|
|
data/spec/page_spec.rb
CHANGED
@@ -14,12 +14,12 @@ describe GoCardless::Page do
|
|
14
14
|
|
15
15
|
context "when there is next page available" do
|
16
16
|
let(:links) {{ "next" => 2, "last" => 2 }}
|
17
|
-
it { should
|
17
|
+
it { should be_truthy }
|
18
18
|
end
|
19
19
|
|
20
20
|
context "when there is no next page" do
|
21
21
|
let(:links) {{ "previous" => 1, "first" => 1 }}
|
22
|
-
it { should
|
22
|
+
it { should be_falsey }
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
data/spec/resource_spec.rb
CHANGED
@@ -170,8 +170,8 @@ describe GoCardless::Resource do
|
|
170
170
|
end
|
171
171
|
|
172
172
|
it "#persisted? works" do
|
173
|
-
GoCardless::Resource.new.persisted?.should
|
174
|
-
GoCardless::Resource.new(:id => 1).persisted?.should
|
173
|
+
GoCardless::Resource.new.persisted?.should be_falsey
|
174
|
+
GoCardless::Resource.new(:id => 1).persisted?.should be_truthy
|
175
175
|
end
|
176
176
|
|
177
177
|
describe "#save" do
|
@@ -288,8 +288,8 @@ describe GoCardless::Resource do
|
|
288
288
|
|
289
289
|
describe "resource permissions" do
|
290
290
|
it "are not given by default" do
|
291
|
-
GoCardless::Resource.creatable?.should
|
292
|
-
GoCardless::Resource.updatable?.should
|
291
|
+
GoCardless::Resource.creatable?.should be_falsey
|
292
|
+
GoCardless::Resource.updatable?.should be_falsey
|
293
293
|
end
|
294
294
|
|
295
295
|
it "are present when specified" do
|
@@ -301,14 +301,14 @@ describe GoCardless::Resource do
|
|
301
301
|
updatable
|
302
302
|
end
|
303
303
|
|
304
|
-
CreatableResource.creatable?.should
|
305
|
-
CreatableResource.updatable?.should
|
304
|
+
CreatableResource.creatable?.should be_truthy
|
305
|
+
CreatableResource.updatable?.should be_falsey
|
306
306
|
|
307
|
-
UpdatableResource.creatable?.should
|
308
|
-
UpdatableResource.updatable?.should
|
307
|
+
UpdatableResource.creatable?.should be_falsey
|
308
|
+
UpdatableResource.updatable?.should be_truthy
|
309
309
|
|
310
|
-
GoCardless::Resource.creatable?.should
|
311
|
-
GoCardless::Resource.updatable?.should
|
310
|
+
GoCardless::Resource.creatable?.should be_falsey
|
311
|
+
GoCardless::Resource.updatable?.should be_falsey
|
312
312
|
end
|
313
313
|
end
|
314
314
|
|
data/spec/spec_helper.rb
CHANGED
@@ -17,12 +17,12 @@ shared_examples_for "it has a query method for" do |status|
|
|
17
17
|
describe "##{status}?" do
|
18
18
|
context "when #{status}" do
|
19
19
|
let(:object) { described_class.new(:status => status) }
|
20
|
-
specify { object.send("#{status}?").should
|
20
|
+
specify { object.send("#{status}?").should be_truthy }
|
21
21
|
end
|
22
22
|
|
23
23
|
context "when not #{status}" do
|
24
24
|
let(:object) { described_class.new }
|
25
|
-
specify { object.send("#{status}?").should
|
25
|
+
specify { object.send("#{status}?").should be_falsey }
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/spec/utils_spec.rb
CHANGED
@@ -26,6 +26,16 @@ describe GoCardless::Utils do
|
|
26
26
|
GoCardless::Utils.singularize("cacti").should == "cactus"
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
describe '.secure_compare' do
|
31
|
+
it 'is true for the same strings' do
|
32
|
+
GoCardless::Utils.secure_compare('hello', 'hello').should be_truthy
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'is false for different strings' do
|
36
|
+
GoCardless::Utils.secure_compare('hello', 'banjo').should be_falsey
|
37
|
+
end
|
38
|
+
end
|
29
39
|
end
|
30
40
|
|
31
41
|
describe "hash helpers" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gocardless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.11.
|
4
|
+
version: 1.11.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Harry Marr
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-10-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: oauth2
|
@@ -157,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
157
|
version: '0'
|
158
158
|
requirements: []
|
159
159
|
rubyforge_project:
|
160
|
-
rubygems_version: 2.
|
160
|
+
rubygems_version: 2.4.2
|
161
161
|
signing_key:
|
162
162
|
specification_version: 4
|
163
163
|
summary: Ruby wrapper for the GoCardless API
|