gocardless 1.11.1 → 1.11.2

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 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