Browse files

Added a response_params_valid? method to check that resource response

data is valid (including signature)
  • Loading branch information...
1 parent 1ee0336 commit 200c948496b32784bba30f2ccd6624bbd0d4710c James Wheatley committed Jun 18, 2012
Showing with 73 additions and 10 deletions.
  1. +31 −10 lib/gocardless/client.rb
  2. +42 −0 spec/client_spec.rb
View
41 lib/gocardless/client.rb
@@ -220,16 +220,7 @@ def new_bill_url(params)
# @param [Hash] params the response parameters returned by the API server
# @return [Resource] the confirmed resource object
def confirm_resource(params)
- # Create a new hash in case is a HashWithIndifferentAccess (keys are
- # always a String)
- params = Utils.symbolize_keys(Hash[params])
- # Only pull out the relevant parameters, other won't be included in the
- # signature so will cause false negatives
- keys = [:resource_id, :resource_type, :resource_uri, :state, :signature]
- params = Hash[params.select { |k,v| keys.include? k }]
- (keys - [:state]).each do |key|
- raise ArgumentError, "Parameters missing #{key}" if !params.key?(key)
- end
+ params = prepare_params(params)
if signature_valid?(params)
data = {
@@ -254,6 +245,17 @@ def confirm_resource(params)
end
+ # Check that resource response data includes a valid signature.
+ #
+ # @param [Hash] params the response parameters returned by the API server
+ # @return [Boolean] true when valid, false otherwise
+ def response_params_valid?(params)
+ params = prepare_params(params)
+
+ signature_valid?(params)
+ end
+
+
# Validates the payload contents of a webhook request.
#
# @param [Hash] params the contents of payload of the webhook
@@ -310,6 +312,25 @@ def sign_params(params)
params
end
+ # Prepare a Hash of parameters for singing. Presence of required
+ # parameters is checked and the others are discarded.
+ #
+ # @param [Hash] params the parameters to be prepared for signing
+ # @return [Hash] the prepared parameters
+ def prepare_params(params)
+ # Create a new hash in case is a HashWithIndifferentAccess (keys are
+ # always a String)
+ params = Utils.symbolize_keys(Hash[params])
+ # Only pull out the relevant parameters, other won't be included in the
+ # signature so will cause false negatives
+ keys = [:resource_id, :resource_type, :resource_uri, :state, :signature]
+ params = Hash[params.select { |k,v| keys.include? k }]
+ (keys - [:state]).each do |key|
+ raise ArgumentError, "Parameters missing #{key}" if !params.key?(key)
+ end
+ params
+ end
+
# Check if a hash's :signature is valid
#
# @param [Hash] params the parameters to check
View
42 spec/client_spec.rb
@@ -333,6 +333,48 @@
end
end
+ describe "#response_params_valid?" do
+ before :each do
+ @params = {
+ :resource_id => '1',
+ :resource_uri => 'a',
+ :resource_type => 'subscription',
+ }
+ end
+
+ [:resource_id, :resource_uri, :resource_type].each do |param|
+ it "fails when :#{param} is missing" do
+ p = @params.tap { |d| d.delete(param) }
+ expect { @client.response_params_valid? p }.to raise_exception ArgumentError
+ end
+ end
+
+ it "does not fail when keys are strings in a HashWithIndiferentAccess" do
+ params = {'resource_id' => 1,
+ 'resource_uri' => 'a',
+ 'resource_type' => 'subscription',
+ 'signature' => 'foo'}
+ params_indifferent_access = HashWithIndifferentAccess.new(params)
+ expect { @client.response_params_valid? params_indifferent_access }.to_not raise_exception ArgumentError
+ end
+
+ it "rejects other params not required for the signature" do
+ @client.expects(:signature_valid?).returns(true).with(hash) do |hash|
+ !hash.keys.include?(:foo) && !hash.keys.include?('foo')
+ end
+
+ @client.response_params_valid?(@client.send(:sign_params, @params).merge('foo' => 'bar'))
+ end
+
+ it "returns false when the signature is invalid" do
+ @client.response_params_valid?({:signature => 'xxx'}.merge(@params)).should be_false
+ end
+
+ it "returns true when the signature is valid" do
+ @client.response_params_valid?(@client.send(:sign_params, @params)).should be_true
+ end
+ end
+
it "#generate_nonce should generate a random string" do
@client.send(:generate_nonce).should_not == @client.send(:generate_nonce)
end

0 comments on commit 200c948

Please sign in to comment.