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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b3a88d8a7aa3c33e45904af4ef911e8cb130769d
4
- data.tar.gz: b10e98e102e8b39325c0d63f361c45887ea83ea9
3
+ metadata.gz: 417cec8542edd246281e1e82b45294ad06d09a5e
4
+ data.tar.gz: 2dae626c784514a1b722dbb348bd782e954f7c46
5
5
  SHA512:
6
- metadata.gz: 5b29a3f20bb862f1068fd4a117bbd7f6354e05cb58d6db2a80b7b99e89e0811d4b0b68c3ba27f90b8936df8d441e660f5e7b7540dac6ebe074fbe0aeab9ca8a7
7
- data.tar.gz: c9fd6c36424dbeed58426043b92d7669067f0199fe904b58f06f338daf7713b500ce3f8ab493c276e741a9386180c28eb6d549eda8edf03d7ea2789478a8f0ad
6
+ metadata.gz: d47705fcf702d7fb7ed80a1e847b7953c4b235f6bb78d16961978c97166eaa9c9b1d790dde027e3a2cac7109170e5b2063e1fac1a4588a576aeb143314a68795
7
+ data.tar.gz: b8c4cc2cc8ad7aebf8586a8f9b901e160116b03039c1c820b5c3bdab1848bddd233e061c07ded755d63f67f5df2ae096dad29169f2c1ad9ffc221ab8932eccf2
@@ -1,3 +1,8 @@
1
+ ## 1.11.2 - October 27, 2014
2
+
3
+ - Use a constant time string comparison to avoid timing attacks
4
+ - Switch to Rspec3 style param checking
5
+
1
6
  ## 1.11.1 - August 22, 2014
2
7
 
3
8
  - Fix bug affecting paginated sub-resources
@@ -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] == signature
421
+ Utils.secure_compare(sign_params(params)[:signature], signature)
422
422
  end
423
423
 
424
424
  # Generate a random base64-encoded string
@@ -82,7 +82,7 @@ module GoCardless
82
82
  end * '&'
83
83
  end
84
84
 
85
- # Given a Hash of parameters, normalize then (flatten and convert to a
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
@@ -1,3 +1,3 @@
1
1
  module GoCardless
2
- VERSION = '1.11.1'.freeze
2
+ VERSION = '1.11.2'.freeze
3
3
  end
@@ -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).with { |p,o| p =~ %r|/api/v1/test| }.and_return(r)
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).with { |p,opts| opts[:body] == '{"a":1}' }.and_return(r)
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).with { |p,opts| opts[:body] == '{"a":1}' }.and_return(r)
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).with { |p,o| p == merchant_url }.and_return response
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 be_true
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 be_false
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).once.with do |type, path, opts|
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 be_false
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 be_true
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 be_true
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 be_false
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 be_true
559
+ should be_truthy
552
560
  end
553
561
  end
554
562
 
@@ -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 be_true }
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 be_false }
22
+ it { should be_falsey }
23
23
  end
24
24
  end
25
25
 
@@ -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 be_false
174
- GoCardless::Resource.new(:id => 1).persisted?.should be_true
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 be_false
292
- GoCardless::Resource.updatable?.should be_false
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 be_true
305
- CreatableResource.updatable?.should be_false
304
+ CreatableResource.creatable?.should be_truthy
305
+ CreatableResource.updatable?.should be_falsey
306
306
 
307
- UpdatableResource.creatable?.should be_false
308
- UpdatableResource.updatable?.should be_true
307
+ UpdatableResource.creatable?.should be_falsey
308
+ UpdatableResource.updatable?.should be_truthy
309
309
 
310
- GoCardless::Resource.creatable?.should be_false
311
- GoCardless::Resource.updatable?.should be_false
310
+ GoCardless::Resource.creatable?.should be_falsey
311
+ GoCardless::Resource.updatable?.should be_falsey
312
312
  end
313
313
  end
314
314
 
@@ -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 be_true }
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 be_false }
25
+ specify { object.send("#{status}?").should be_falsey }
26
26
  end
27
27
  end
28
28
  end
@@ -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.1
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-08-22 00:00:00.000000000 Z
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.2.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