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 collapse

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

#calculate_billing_address_signature(parameters, shared_secret = nil) ⇒ String

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



303
304
305
306
307
# File 'lib/adyen/form.rb', line 303

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::Util.hmac_base64(shared_secret, calculate_billing_address_signature_string(parameters[:billing_address]))
end

#calculate_billing_address_signature_string(parameters) ⇒ String

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.



273
274
275
276
277
# File 'lib/adyen/form.rb', line 273

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

#calculate_delivery_address_signature(parameters, shared_secret = nil) ⇒ String

Calculates the delivery address request signature for the given delivery 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 delivery address request parameters as the deliveryAddressSig parameter; the shared secret should of course not be included.

Parameters:

  • parameters (Hash)

    The delivery address parameters for which to calculate the delivery 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 delivery address request

Raises:

  • (ArgumentError)

    Thrown if shared_secret is empty



323
324
325
326
327
# File 'lib/adyen/form.rb', line 323

def calculate_delivery_address_signature(parameters, shared_secret = nil)
  shared_secret ||= parameters.delete(:shared_secret)
  raise ArgumentError, "Cannot calculate delivery address request signature with empty shared_secret" if shared_secret.to_s.empty?
  Adyen::Util.hmac_base64(shared_secret, calculate_delivery_address_signature_string(parameters[:delivery_address]))
end

#calculate_delivery_address_signature_string(parameters) ⇒ String

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 delivery address request.

Returns:

  • (String)

    The string for which the siganture is calculated.



283
284
285
286
287
# File 'lib/adyen/form.rb', line 283

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

#calculate_open_invoice_signature(parameters, shared_secret = nil) ⇒ Object

Raises:

  • (ArgumentError)


349
350
351
352
353
354
# File 'lib/adyen/form.rb', line 349

def calculate_open_invoice_signature(parameters, shared_secret = nil)
  shared_secret ||= parameters.delete(:shared_secret)
  raise ArgumentError, "Cannot calculate open invoice request signature with empty shared_secret" if shared_secret.to_s.empty?
  merchant_sig = calculate_signature(parameters, shared_secret)
  Adyen::Util.hmac_base64(shared_secret, calculate_open_invoice_signature_string(merchant_sig, parameters[:openinvoicedata]))
end

#calculate_open_invoice_signature_string(merchant_sig, parameters) ⇒ Object



343
344
345
346
347
# File 'lib/adyen/form.rb', line 343

def calculate_open_invoice_signature_string(merchant_sig, parameters)
  flattened = Adyen::Util.flatten(:merchant_sig => merchant_sig, :openinvoicedata => parameters)
  pairs = flattened.to_a.sort
  pairs.transpose.map { |it| it.join(':') }.join('|')
end

#calculate_shopper_signature(parameters, shared_secret = nil) ⇒ Object

Raises:

  • (ArgumentError)


337
338
339
340
341
# File 'lib/adyen/form.rb', line 337

def calculate_shopper_signature(parameters, shared_secret = nil)
  shared_secret ||= parameters.delete(:shared_secret)
  raise ArgumentError, "Cannot calculate shopper request signature with empty shared_secret" if shared_secret.to_s.empty?
  Adyen::Util.hmac_base64(shared_secret, calculate_shopper_signature_string(parameters[:shopper]))
end

#calculate_shopper_signature_string(parameters) ⇒ Object

shopperSig: shopper.firstName + shopper.infix + shopper.lastName + shopper.gender + shopper.dateOfBirthDayOfMonth + shopper.dateOfBirthMonth + shopper.dateOfBirthYear + shopper.telephoneNumber (Note that you can send only shopper.firstName and shopper.lastName if you like. Do NOT include shopperSocialSecurityNumber in the shopperSig!)



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

def calculate_shopper_signature_string(parameters)
  %w(first_name infix last_name gender date_of_birth_day_of_month date_of_birth_month date_of_birth_year telephone_number).map do |key|
    parameters[key.to_sym]
  end.join
end

#calculate_signature(parameters, shared_secret = nil) ⇒ String

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



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

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::Util.hmac_base64(shared_secret, calculate_signature_string(parameters))
end

#calculate_signature_string(parameters) ⇒ String

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.



236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/adyen/form.rb', line 236

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[:delivery_address_type].to_s <<
                         parameters[:shopper_type].to_s         << parameters[:offset].to_s
end

#do_parameter_transformations!(parameters = {}) ⇒ Object

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



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

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::Util.gzip_base64(parameters.delete(:order_data_raw)) if parameters[:order_data_raw]
  parameters[:ship_before_date]   = Adyen::Util.format_date(parameters[:ship_before_date])
  parameters[:session_validity]   = Adyen::Util.format_timestamp(parameters[:session_validity])
end

#domain(environment = nil) ⇒ String

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


48
49
50
51
# File 'lib/adyen/form.rb', line 48

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

#flat_payment_parameters(parameters = {}) ⇒ Hash

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



145
146
147
# File 'lib/adyen/form.rb', line 145

def flat_payment_parameters(parameters = {})
  Adyen::Util.flatten(payment_parameters(parameters))
end

#hidden_fields(parameters = {}) ⇒ String

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.



218
219
220
221
222
223
224
225
226
# File 'lib/adyen/form.rb', line 218

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

#payment_methods_url(parameters = {}) ⇒ String

Returns an absolute URL very similar to the one returned by Adyen::Form.redirect_url except that it uses the directory.shtml call which returns a list of all available payment methods

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.

See Also:

  • redirect_url


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

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

#payment_parameters(parameters = {}, shared_secret = nil) ⇒ Hash

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.



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/adyen/form.rb', line 107

def payment_parameters(parameters = {}, shared_secret = nil)
  raise ArgumentError, "Cannot generate form: parameters should be a hash!" unless parameters.is_a?(Hash)
  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

  if parameters[:delivery_address]
    parameters[:delivery_address_sig] = calculate_delivery_address_signature(parameters, shared_secret)
  end

  if parameters[:shopper]
    parameters[:shopper_sig] = calculate_shopper_signature(parameters, shared_secret)
  end

  if parameters[:openinvoicedata]
    parameters[:openinvoicedata][:sig] = calculate_open_invoice_signature(parameters, shared_secret)
  end

  return parameters
end

#redirect_signature(params, shared_secret = nil) ⇒ String

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



377
378
379
380
381
# File 'lib/adyen/form.rb', line 377

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::Util.hmac_base64(shared_secret, redirect_signature_string(params))
end

#redirect_signature_check(params, shared_secret = nil) ⇒ true, false

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.

Raises:

  • (ArgumentError)


413
414
415
416
417
# File 'lib/adyen/form.rb', line 413

def redirect_signature_check(params, shared_secret = nil)
  raise ArgumentError, "params should be a Hash" unless params.is_a?(Hash)
  raise ArgumentError, "params should contain :merchantSig" unless params.key?('merchantSig')
  params['merchantSig'] == redirect_signature(params, shared_secret)
end

#redirect_signature_string(params) ⇒ String

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.



363
364
365
366
# File 'lib/adyen/form.rb', line 363

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

#redirect_url(parameters = {}) ⇒ String

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.



177
178
179
180
181
# File 'lib/adyen/form.rb', line 177

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

#url(environment = nil, payment_flow = nil) ⇒ String

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


64
65
66
67
# File 'lib/adyen/form.rb', line 64

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