Module: Adyen::Form

Extended by:
Form
Included in:
Form
Defined in:
lib/adyen/form.rb

Overview

The Adyen::Form module contains all functionality that is used to send payment requests to the Adyen payment system, using either a HTML form (see hidden_fields) or a HTTP redirect (see redirect_url).

Moreover, this module contains the method redirect_signature_check to check the request, that is made to your website after the visitor has made his payment on the Adyen system, for genuinity.

You can use different skins in Adyen to define different payment environments. You can register these skins under a custom name in the module. The other methods will automatically use this information (i.e. the skin code and the shared secret) if it is available. Otherwise, you have to provide it yourself for every method call you make. See Configuration#register_form_skin for more information.

See Also:

Constant Summary

ACTION_DOMAIN =

The DOMAIN of the Adyen payment system that still requires the current Adyen enviroment.

"%s.adyen.com"
ACTION_URL =

The URL of the Adyen payment system that still requires the current domain and payment flow to be filled.

"https://%s/hpp/%s.shtml"

Instance Method Summary (collapse)

Instance Method Details

- (String) calculate_billing_address_signature(parameters, shared_secret = nil)

Calculates the billing address request signature for the given billing address parameters.

This signature is used by Adyen to check whether the request is genuinely originating from you. The resulting signature should be included in the billing address request parameters as the billingAddressSig parameter; the shared secret should of course not be included.

Parameters:

  • parameters (Hash)

    The billing address parameters for which to calculate the billing address request signature.

  • shared_secret (String) (defaults to: nil)

    The shared secret to use for this signature. It should correspond with the skin_code parameter. This parameter can be left out if the shared_secret is included as key in the parameters.

Returns:

  • (String)

    The signature of the billing address request

Raises:

  • (ArgumentError)

    Thrown if shared_secret is empty



263
264
265
266
267
# File 'lib/adyen/form.rb', line 263

def calculate_billing_address_signature(parameters, shared_secret = nil)
  shared_secret ||= parameters.delete(:shared_secret)
  raise ArgumentError, "Cannot calculate billing address request signature with empty shared_secret" if shared_secret.to_s.empty?
  Adyen::Encoding.hmac_base64(shared_secret, calculate_billing_address_signature_string(parameters[:billing_address]))
end

- (String) calculate_billing_address_signature_string(parameters)

Generates the string that is used to calculate the request signature. This signature is used by Adyen to check whether the request is genuinely originating from you.

Parameters:

  • parameters (Hash)

    The parameters that will be included in the billing address request.

Returns:

  • (String)

    The string for which the siganture is calculated.



243
244
245
246
247
# File 'lib/adyen/form.rb', line 243

def calculate_billing_address_signature_string(parameters)
  %w(street house_number_or_name city postal_code state_or_province country).map do |key|
    parameters[key.to_sym]
  end.join
end

- (String) calculate_signature(parameters, shared_secret = nil)

Calculates the payment request signature for the given payment parameters.

This signature is used by Adyen to check whether the request is genuinely originating from you. The resulting signature should be included in the payment request parameters as the merchantSig parameter; the shared secret should of course not be included.

Parameters:

  • parameters (Hash)

    The payment parameters for which to calculate the payment request signature.

  • shared_secret (String) (defaults to: nil)

    The shared secret to use for this signature. It should correspond with the skin_code parameter. This parameter can be left out if the shared_secret is included as key in the parameters.

Returns:

  • (String)

    The signature of the payment request

Raises:

  • (ArgumentError)

    Thrown if shared_secret is empty



233
234
235
236
237
# File 'lib/adyen/form.rb', line 233

def calculate_signature(parameters, shared_secret = nil)
  shared_secret ||= parameters.delete(:shared_secret)
  raise ArgumentError, "Cannot calculate payment request signature with empty shared_secret" if shared_secret.to_s.empty?
  Adyen::Encoding.hmac_base64(shared_secret, calculate_signature_string(parameters))
end

- (String) calculate_signature_string(parameters)

Generates the string that is used to calculate the request signature. This signature is used by Adyen to check whether the request is genuinely originating from you.

Parameters:

  • parameters (Hash)

    The parameters that will be included in the payment request.

Returns:

  • (String)

    The string for which the siganture is calculated.



207
208
209
210
211
212
213
214
215
216
217
# File 'lib/adyen/form.rb', line 207

def calculate_signature_string(parameters)
  merchant_sig_string = ""
  merchant_sig_string << parameters[:payment_amount].to_s       << parameters[:currency_code].to_s        <<
                         parameters[:ship_before_date].to_s     << parameters[:merchant_reference].to_s   <<
                         parameters[:skin_code].to_s            << parameters[:merchant_account].to_s     <<
                         parameters[:session_validity].to_s     << parameters[:shopper_email].to_s        <<
                         parameters[:shopper_reference].to_s    << parameters[:recurring_contract].to_s   <<
                         parameters[:allowed_methods].to_s      << parameters[:blocked_methods].to_s      <<
                         parameters[:shopper_statement].to_s    << parameters[:merchant_return_data].to_s <<
                         parameters[:billing_address_type].to_s << parameters[:offset].to_s
end

- (String) camelize(identifier)

Returns the camelized version of a string.

Parameters:

  • identifier (:to_s)

    The identifier to turn to camelcase

Returns:

  • (String)

    The camelcase version of the identifier provided.



333
334
335
# File 'lib/adyen/form.rb', line 333

def camelize(identifier)
  identifier.to_s.gsub(/_(.)/) { $1.upcase }
end

- (Object) do_parameter_transformations!(parameters = {})

Transforms the payment parameters hash to be in the correct format. It will also include the Adyen::Configuration#default_form_params hash. Finally, switches the :skin parameter out for the :skin_code and :shared_secret parameter using the list of registered skins.

Parameters:

  • parameters (Hash) (defaults to: {})

    The payment parameters hash to transform



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/adyen/form.rb', line 78

def do_parameter_transformations!(parameters = {})
  parameters.replace(Adyen.configuration.default_form_params.merge(parameters))

  if parameters[:skin]
    skin = Adyen.configuration.form_skin_by_name(parameters.delete(:skin))
    parameters[:skin_code]     ||= skin[:skin_code]
    parameters[:shared_secret] ||= skin[:shared_secret]
    parameters.merge!(skin[:default_form_params])
  end

  parameters[:recurring_contract] = 'RECURRING' if parameters.delete(:recurring) == true
  parameters[:order_data]         = Adyen::Encoding.gzip_base64(parameters.delete(:order_data_raw)) if parameters[:order_data_raw]
  parameters[:ship_before_date]   = Adyen::Formatter::DateTime.fmt_date(parameters[:ship_before_date])
  parameters[:session_validity]   = Adyen::Formatter::DateTime.fmt_time(parameters[:session_validity])
end

- (String) domain(environment = nil)

Returns the DOMAIN of the Adyen payment system, adjusted for an Adyen environment.

Parameters:

  • environment (String) (defaults to: nil)

    The Adyen environment to use. This parameter can be left out, in which case the 'current' environment will be used.

Returns:

  • (String)

    The domain of the Adyen payment system that can be used for payment forms or redirects.

See Also:

  • environment
  • redirect_url


46
47
48
49
# File 'lib/adyen/form.rb', line 46

def domain(environment = nil)
  environment  ||= Adyen.configuration.environment
  (Adyen.configuration.payment_flow_domain || ACTION_DOMAIN) % [environment.to_s]
end

- (Hash) flat_payment_parameters(parameters = {})

Transforms and flattens payment parameters to be in the correct format which is understood and accepted by adyen

Parameters:

Returns:

  • (Hash)

    The payment parameters flatten, with camelized and prefixed key, stringified value



130
131
132
# File 'lib/adyen/form.rb', line 130

def flat_payment_parameters(parameters = {})
  flatten(payment_parameters(parameters))
end

- (Hash) flatten(parameters, prefix = "", return_hash = {})

Transforms the nested parameters Hash into a 'flat' Hash which is understood by adyen. This is:

* all keys are camelized
* all keys are  stringified
* nested hash is flattened, keys are prefixed with root key

Examples:

flatten {:billing_address => { :street => 'My Street'}}

# resolves in:
{'billingAddress.street' =>  'My Street'}

Parameters:

  • parameters (Hash)

    The payment parameters which to transform

  • prefix (String) (defaults to: "")

    The prefix to add to the key

  • return_hash (Hash) (defaults to: {})

    The new hash which is retruned (needed for recursive calls)

Returns:

  • (Hash)

    The return_hash filled with camelized and prefixed key, stringified value



352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/adyen/form.rb', line 352

def flatten(parameters, prefix = "", return_hash = {})
  parameters ||= {}
  parameters.inject(return_hash) do |hash, (key, value)|
    key = "#{prefix}#{camelize(key)}"
    if value.is_a?(Hash)
      flatten(value, "#{key}.", return_hash)
    else
      hash[key] = value.to_s
    end
    hash
  end
end

- (String) hidden_fields(parameters = {})

Returns a HTML snippet of hidden INPUT tags with the provided payment parameters. The snippet can be included in a payment form that POSTs to the Adyen payment system.

The payment parameters that are provided to this method will be merged with the Configuration#default_form_params hash. The default parameter values will be overrided if another value is provided to this method.

You do not have to provide the :merchant_sig parameter: it will be calculated automatically if you provide either a registered skin name as the :skin parameter or provide both the :skin_code and :shared_secret parameters.

Examples:

<% form_tag(Adyen::Form.url) do %>
  <%= Adyen::Form.hidden_fields(:skin => :my_skin, :currency_code => 'USD',
        :payment_amount => 1000, ...) %>
  <%= submit_tag("Pay invoice")
<% end %>

Parameters:

  • parameters (Hash) (defaults to: {})

    The payment parameters to include in the payment request.

Returns:

  • (String)

    An HTML snippet that can be included in a form that POSTs to the Adyen payment system.



189
190
191
192
193
194
195
196
197
# File 'lib/adyen/form.rb', line 189

def hidden_fields(parameters = {})

  # Generate a hidden input tag per parameter, join them by newlines.
  form_str = flat_payment_parameters(parameters).map { |key, value|
    "<input type=\"hidden\" name=\"#{CGI.escapeHTML(key)}\" value=\"#{CGI.escapeHTML(value)}\" />"
  }.join("\n")

  form_str.respond_to?(:html_safe) ? form_str.html_safe : form_str
end

- (Hash) payment_parameters(parameters = {}, shared_secret = nil)

Transforms the payment parameters to be in the correct format and calculates the merchant signature parameter. It also does some basic health checks on the parameters hash.

Parameters:

  • parameters (Hash) (defaults to: {})

    The payment parameters. The parameters set in the Configuration#default_form_params hash will be included automatically.

  • shared_secret (String) (defaults to: nil)

    The shared secret that should be used to calculate the payment request signature. This parameter can be left if the skin that is used is registered (see Configuration#register_form_skin), or if the shared secret is provided as the :shared_secret parameter.

Returns:

  • (Hash)

    The payment parameters with the :merchant_signature parameter set.

Raises:

  • (ArgumentError)

    Thrown if some parameter health check fails.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/adyen/form.rb', line 105

def payment_parameters(parameters = {}, shared_secret = nil)
  do_parameter_transformations!(parameters)

  raise ArgumentError, "Cannot generate form: :currency code attribute not found!"         unless parameters[:currency_code]
  raise ArgumentError, "Cannot generate form: :payment_amount code attribute not found!"   unless parameters[:payment_amount]
  raise ArgumentError, "Cannot generate form: :merchant_account attribute not found!"      unless parameters[:merchant_account]
  raise ArgumentError, "Cannot generate form: :skin_code attribute not found!"             unless parameters[:skin_code]

  # Calculate the merchant signature using the shared secret.
  shared_secret ||= parameters.delete(:shared_secret)
  raise ArgumentError, "Cannot calculate payment request signature without shared secret!" unless shared_secret
  parameters[:merchant_sig] = calculate_signature(parameters, shared_secret)

  if parameters[:billing_address]
    parameters[:billing_address_sig] = calculate_billing_address_signature(parameters, shared_secret)
  end

  return parameters
end

- (String) redirect_signature(params, shared_secret = nil)

Computes the redirect signature using the request parameters, so that the redirect can be checked for forgery.

Parameters:

  • params (Hash)

    A hash of HTTP GET parameters for the redirect request.

  • shared_secret (String) (defaults to: nil)

    The shared secret for the Adyen skin that was used for the original payment form. You can leave this out of the skin is registered using the register_skin method.

Returns:

  • (String)

    The redirect signature

Raises:

  • (ArgumentError)

    Thrown if shared_secret is empty



290
291
292
293
294
# File 'lib/adyen/form.rb', line 290

def redirect_signature(params, shared_secret = nil)
  shared_secret ||= Adyen.configuration.form_skin_shared_secret_by_code(params[:skinCode])
  raise ArgumentError, "Cannot compute redirect signature with empty shared_secret" if shared_secret.to_s.empty?
  Adyen::Encoding.hmac_base64(shared_secret, redirect_signature_string(params))
end

- (true, false) redirect_signature_check(params, shared_secret = nil)

Checks the redirect signature for this request by calcultating the signature from the provided parameters, and comparing it to the signature provided in the merchantSig parameter.

If this method returns false, the request could be a forgery and should not be handled. Therefore, you should include this check in a before_filter, and raise an error of the signature check fails.

Examples:

class PaymentsController < ApplicationController
  before_filter :check_signature, :only => [:return_from_adyen]

  def return_from_adyen
    @invoice = Invoice.find(params[:merchantReference])
    @invoice.set_paid! if params[:authResult] == 'AUTHORISED'
  end

  private

  def check_signature
    raise "Forgery!" unless Adyen::Form.redirect_signature_check(params)
  end
end

Parameters:

  • params (Hash)

    params A hash of HTTP GET parameters for the redirect request. This should include the :merchantSig parameter, which contains the signature.

  • shared_secret (String) (defaults to: nil)

    The shared secret for the Adyen skin that was used for the original payment form. You can leave this out of the skin is registered using the Configuration#register_form_skin method.

Returns:

  • (true, false)

    Returns true only if the signature in the parameters is correct.



326
327
328
# File 'lib/adyen/form.rb', line 326

def redirect_signature_check(params, shared_secret = nil)
  params[:merchantSig] == redirect_signature(params, shared_secret)
end

- (String) redirect_signature_string(params)

Generates the string for which the redirect signature is calculated, using the request paramaters.

Parameters:

  • params (Hash)

    A hash of HTTP GET parameters for the redirect request.

Returns:

  • (String)

    The signature string.



276
277
278
279
# File 'lib/adyen/form.rb', line 276

def redirect_signature_string(params)
  params[:authResult].to_s + params[:pspReference].to_s + params[:merchantReference].to_s +
    params[:skinCode].to_s + params[:merchantReturnData].to_s
end

- (String) redirect_url(parameters = {})

Returns an absolute URL to the Adyen payment system, with the payment parameters included as GET parameters in the URL. The URL also depends on the current Adyen enviroment.

The payment parameters that are provided to this method will be merged with the Configuration#default_form_params hash. The default parameter values will be overrided if another value is provided to this method.

You do not have to provide the :merchant_sig parameter: it will be calculated automatically if you provide either a registered skin name as the :skin parameter or provide both the :skin_code and :shared_secret parameters.

Note that Internet Explorer has a maximum length for URLs it can handle (2083 characters). Make sure that the URL is not longer than this limit if you want your site to work in IE.

Examples:


def pay
  # Genarate a URL to redirect to Adyen's payment system.
  adyen_url = Adyen::Form.redirect_url(:skin => :my_skin, :currency_code => 'USD',
        :payment_amount => 1000, merchant_account => 'MyMerchant', ... )

  respond_to do |format|
    format.html { redirect_to(adyen_url) }
  end
end

Parameters:

  • parameters (Hash) (defaults to: {})

    The payment parameters to include in the payment request.

Returns:

  • (String)

    An absolute URL to redirect to the Adyen payment system.



162
163
164
165
166
# File 'lib/adyen/form.rb', line 162

def redirect_url(parameters = {})
  url + '?' + flat_payment_parameters(parameters).map { |(k, v)|
    "#{k}=#{CGI.escape(v)}"
  }.join('&')
end

- (String) url(environment = nil, payment_flow = nil)

Returns the URL of the Adyen payment system, adjusted for an Adyen environment.

Parameters:

  • environment (String) (defaults to: nil)

    The Adyen environment to use. This parameter can be left out, in which case the 'current' environment will be used.

  • payment_flow (String) (defaults to: nil)

    The Adyen payment type to use. This parameter can be left out, in which case the default payment type will be used.

Returns:

  • (String)

    The absolute URL of the Adyen payment system that can be used for payment forms or redirects.

See Also:

  • environment
  • domain
  • redirect_url


62
63
64
65
# File 'lib/adyen/form.rb', line 62

def url(environment = nil, payment_flow = nil)
  payment_flow ||= Adyen.configuration.payment_flow
  Adyen::Form::ACTION_URL % [domain(environment), payment_flow.to_s]
end