module Adyen::Form
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 {Adyen::Form.hidden_fields}) or a HTTP redirect (see {Adyen::Form.redirect_url}).
Moreover, this module contains the method {Adyen::Form.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 {Adyen::Configuration#register_form_skin} for more information.
@see Adyen::Configuration#register_form_skin
@see Adyen::Form.hidden_fields
@see Adyen::Form.redirect_url
@see Adyen::Form.redirect_signature_check
Constants
Public Instance Methods
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.
@param [Hash] parameters The billing address parameters for which to calculate
the billing address request signature.
@param [String] shared_secret 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.
@return [String] The signature of the billing address request @raise [ArgumentError] Thrown if shared_secret is empty
# File lib/adyen/form.rb 303 def calculate_billing_address_signature(parameters, shared_secret = nil) 304 shared_secret ||= parameters.delete(:shared_secret) 305 raise ArgumentError, "Cannot calculate billing address request signature with empty shared_secret" if shared_secret.to_s.empty? 306 Adyen::Util.hmac_base64(shared_secret, calculate_billing_address_signature_string(parameters[:billing_address])) 307 end
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. @param [Hash] parameters The parameters that will be included in the billing address request. @return [String] The string for which the siganture is calculated.
# File lib/adyen/form.rb 273 def calculate_billing_address_signature_string(parameters) 274 %w(street house_number_or_name city postal_code state_or_province country).map do |key| 275 parameters[key.to_sym] 276 end.join 277 end
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.
@param [Hash] parameters The delivery address parameters for which to calculate
the delivery address request signature.
@param [String] shared_secret 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.
@return [String] The signature of the delivery address request @raise [ArgumentError] Thrown if shared_secret is empty
# File lib/adyen/form.rb 323 def calculate_delivery_address_signature(parameters, shared_secret = nil) 324 shared_secret ||= parameters.delete(:shared_secret) 325 raise ArgumentError, "Cannot calculate delivery address request signature with empty shared_secret" if shared_secret.to_s.empty? 326 Adyen::Util.hmac_base64(shared_secret, calculate_delivery_address_signature_string(parameters[:delivery_address])) 327 end
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. @param [Hash] parameters The parameters that will be included in the delivery address request. @return [String] The string for which the siganture is calculated.
# File lib/adyen/form.rb 283 def calculate_delivery_address_signature_string(parameters) 284 %w(street house_number_or_name city postal_code state_or_province country).map do |key| 285 parameters[key.to_sym] 286 end.join 287 end
# File lib/adyen/form.rb 349 def calculate_open_invoice_signature(parameters, shared_secret = nil) 350 shared_secret ||= parameters.delete(:shared_secret) 351 raise ArgumentError, "Cannot calculate open invoice request signature with empty shared_secret" if shared_secret.to_s.empty? 352 merchant_sig = calculate_signature(parameters, shared_secret) 353 Adyen::Util.hmac_base64(shared_secret, calculate_open_invoice_signature_string(merchant_sig, parameters[:openinvoicedata])) 354 end
# File lib/adyen/form.rb 343 def calculate_open_invoice_signature_string(merchant_sig, parameters) 344 flattened = Adyen::Util.flatten(:merchant_sig => merchant_sig, :openinvoicedata => parameters) 345 pairs = flattened.to_a.sort 346 pairs.transpose.map { |it| it.join(':') }.join('|') 347 end
# File lib/adyen/form.rb 337 def calculate_shopper_signature(parameters, shared_secret = nil) 338 shared_secret ||= parameters.delete(:shared_secret) 339 raise ArgumentError, "Cannot calculate shopper request signature with empty shared_secret" if shared_secret.to_s.empty? 340 Adyen::Util.hmac_base64(shared_secret, calculate_shopper_signature_string(parameters[:shopper])) 341 end
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!)
# File lib/adyen/form.rb 331 def calculate_shopper_signature_string(parameters) 332 %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| 333 parameters[key.to_sym] 334 end.join 335 end
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.
@param [Hash] parameters The payment parameters for which to calculate
the payment request signature.
@param [String] shared_secret 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.
@return [String] The signature of the payment request @raise [ArgumentError] Thrown if shared_secret is empty
# File lib/adyen/form.rb 263 def calculate_signature(parameters, shared_secret = nil) 264 shared_secret ||= parameters.delete(:shared_secret) 265 raise ArgumentError, "Cannot calculate payment request signature with empty shared_secret" if shared_secret.to_s.empty? 266 Adyen::Util.hmac_base64(shared_secret, calculate_signature_string(parameters)) 267 end
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. @param [Hash] parameters The parameters that will be included in the payment request. @return [String] The string for which the siganture is calculated.
# File lib/adyen/form.rb 236 def calculate_signature_string(parameters) 237 merchant_sig_string = "" 238 merchant_sig_string << parameters[:payment_amount].to_s << parameters[:currency_code].to_s << 239 parameters[:ship_before_date].to_s << parameters[:merchant_reference].to_s << 240 parameters[:skin_code].to_s << parameters[:merchant_account].to_s << 241 parameters[:session_validity].to_s << parameters[:shopper_email].to_s << 242 parameters[:shopper_reference].to_s << parameters[:recurring_contract].to_s << 243 parameters[:allowed_methods].to_s << parameters[:blocked_methods].to_s << 244 parameters[:shopper_statement].to_s << parameters[:merchant_return_data].to_s << 245 parameters[:billing_address_type].to_s << parameters[:delivery_address_type].to_s << 246 parameters[:shopper_type].to_s << parameters[:offset].to_s 247 end
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.
@private @param [Hash] parameters The payment parameters hash to transform
# File lib/adyen/form.rb 80 def do_parameter_transformations!(parameters = {}) 81 parameters.replace(Adyen.configuration.default_form_params.merge(parameters)) 82 83 if parameters[:skin] 84 skin = Adyen.configuration.form_skin_by_name(parameters.delete(:skin)) 85 parameters[:skin_code] ||= skin[:skin_code] 86 parameters[:shared_secret] ||= skin[:shared_secret] 87 parameters.merge!(skin[:default_form_params]) 88 end 89 90 parameters[:recurring_contract] = 'RECURRING' if parameters.delete(:recurring) == true 91 parameters[:order_data] = Adyen::Util.gzip_base64(parameters.delete(:order_data_raw)) if parameters[:order_data_raw] 92 parameters[:ship_before_date] = Adyen::Util.format_date(parameters[:ship_before_date]) 93 parameters[:session_validity] = Adyen::Util.format_timestamp(parameters[:session_validity]) 94 end
Returns the DOMAIN of the Adyen
payment system, adjusted for an Adyen
environment.
@param [String] environment The Adyen
environment to use. This parameter can be
left out, in which case the 'current' environment will be used.
@return [String] The domain of the Adyen
payment system that can be used
for payment forms or redirects.
@see Adyen::Form.environment @see Adyen::Form.redirect_url
# File lib/adyen/form.rb 48 def domain(environment = nil) 49 environment ||= Adyen.configuration.environment 50 Adyen.configuration.payment_flow_domain || ACTION_DOMAIN % [environment.to_s] 51 end
Transforms and flattens payment parameters to be in the correct format which is understood and accepted by adyen
@param [Hash] parameters The payment parameters. The parameters set in the
{Adyen::Configuration#default_form_params} hash will be included automatically.
@return [Hash] The payment parameters flatten, with camelized and prefixed key, stringified value
# File lib/adyen/form.rb 145 def flat_payment_parameters(parameters = {}) 146 Adyen::Util.flatten(payment_parameters(parameters)) 147 end
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
@param [Hash] parameters The payment parameters to include in the payment request. @return [String] An absolute URL to redirect to the Adyen
payment system.
# File lib/adyen/form.rb 191 def payment_methods_url(parameters = {}) 192 url(nil, :directory) + '?' + flat_payment_parameters(parameters).map { |(k, v)| 193 "#{k}=#{CGI.escape(v)}" 194 }.join('&') 195 end
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.
@param [Hash] parameters The payment parameters. The parameters set in the
{Adyen::Configuration#default_form_params} hash will be included automatically.
@param [String] shared_secret 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 {Adyen::Configuration#register_form_skin}), or if the shared secret is provided as the +:shared_secret+ parameter.
@return [Hash] The payment parameters with the :merchant_signature
parameter set. @raise [ArgumentError] Thrown if some parameter health check fails.
# File lib/adyen/form.rb 107 def payment_parameters(parameters = {}, shared_secret = nil) 108 raise ArgumentError, "Cannot generate form: parameters should be a hash!" unless parameters.is_a?(Hash) 109 do_parameter_transformations!(parameters) 110 111 raise ArgumentError, "Cannot generate form: :currency code attribute not found!" unless parameters[:currency_code] 112 raise ArgumentError, "Cannot generate form: :payment_amount code attribute not found!" unless parameters[:payment_amount] 113 raise ArgumentError, "Cannot generate form: :merchant_account attribute not found!" unless parameters[:merchant_account] 114 raise ArgumentError, "Cannot generate form: :skin_code attribute not found!" unless parameters[:skin_code] 115 116 # Calculate the merchant signature using the shared secret. 117 shared_secret ||= parameters.delete(:shared_secret) 118 raise ArgumentError, "Cannot calculate payment request signature without shared secret!" unless shared_secret 119 parameters[:merchant_sig] = calculate_signature(parameters, shared_secret) 120 121 if parameters[:billing_address] 122 parameters[:billing_address_sig] = calculate_billing_address_signature(parameters, shared_secret) 123 end 124 125 if parameters[:delivery_address] 126 parameters[:delivery_address_sig] = calculate_delivery_address_signature(parameters, shared_secret) 127 end 128 129 if parameters[:shopper] 130 parameters[:shopper_sig] = calculate_shopper_signature(parameters, shared_secret) 131 end 132 133 if parameters[:openinvoicedata] 134 parameters[:openinvoicedata][:sig] = calculate_open_invoice_signature(parameters, shared_secret) 135 end 136 137 return parameters 138 end
Computes the redirect signature using the request parameters, so that the redirect can be checked for forgery.
@param [Hash] params A hash of HTTP GET parameters for the redirect request. @param [String] shared_secret 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 {Adyen::Form.register_skin} method.
@return [String] The redirect signature @raise [ArgumentError] Thrown if shared_secret is empty
# File lib/adyen/form.rb 377 def redirect_signature(params, shared_secret = nil) 378 shared_secret ||= Adyen.configuration.form_skin_shared_secret_by_code(params['skinCode']) 379 raise ArgumentError, "Cannot compute redirect signature with empty shared_secret" if shared_secret.to_s.empty? 380 Adyen::Util.hmac_base64(shared_secret, redirect_signature_string(params)) 381 end
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.
@example
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
@param [Hash] params params A hash of HTTP GET parameters for the redirect request. This
should include the +:merchantSig+ parameter, which contains the signature.
@param [String] shared_secret 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 {Adyen::Configuration#register_form_skin} method.
@return [true, false] Returns true only if the signature in the parameters is correct.
# File lib/adyen/form.rb 413 def redirect_signature_check(params, shared_secret = nil) 414 raise ArgumentError, "params should be a Hash" unless params.is_a?(Hash) 415 raise ArgumentError, "params should contain :merchantSig" unless params.key?('merchantSig') 416 params['merchantSig'] == redirect_signature(params, shared_secret) 417 end
Generates the string for which the redirect signature is calculated, using the request paramaters. @param [Hash] params A hash of HTTP GET parameters for the redirect request. @return [String] The signature string.
# File lib/adyen/form.rb 363 def redirect_signature_string(params) 364 params['authResult'].to_s + params['pspReference'].to_s + params['merchantReference'].to_s + 365 params['skinCode'].to_s + params['merchantReturnData'].to_s 366 end
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 {Adyen::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.
@example
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
@param [Hash] parameters The payment parameters to include in the payment request. @return [String] An absolute URL to redirect to the Adyen
payment system.
# File lib/adyen/form.rb 177 def redirect_url(parameters = {}) 178 url + '?' + flat_payment_parameters(parameters).map { |(k, v)| 179 "#{k}=#{CGI.escape(v)}" 180 }.join('&') 181 end
Returns the URL of the Adyen
payment system, adjusted for an Adyen
environment.
@param [String] environment The Adyen
environment to use. This parameter can be
left out, in which case the 'current' environment will be used.
@param [String] payment_flow The Adyen
payment type to use. This parameter can be
left out, in which case the default payment type will be used.
@return [String] The absolute URL of the Adyen
payment system that can be used
for payment forms or redirects.
@see Adyen::Form.environment @see Adyen::Form.domain
@see Adyen::Form.redirect_url
# File lib/adyen/form.rb 64 def url(environment = nil, payment_flow = nil) 65 payment_flow ||= Adyen.configuration.payment_flow 66 Adyen::Form::ACTION_URL % [domain(environment), payment_flow.to_s] 67 end