gonow-activemerchant 1.15.0

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.
Files changed (189) hide show
  1. data/CHANGELOG +690 -0
  2. data/CONTRIBUTORS +237 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +165 -0
  5. data/gem-public_cert.pem +20 -0
  6. data/lib/active_merchant.rb +47 -0
  7. data/lib/active_merchant/billing.rb +9 -0
  8. data/lib/active_merchant/billing/avs_result.rb +98 -0
  9. data/lib/active_merchant/billing/base.rb +57 -0
  10. data/lib/active_merchant/billing/check.rb +68 -0
  11. data/lib/active_merchant/billing/credit_card.rb +178 -0
  12. data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
  13. data/lib/active_merchant/billing/credit_card_methods.rb +125 -0
  14. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  15. data/lib/active_merchant/billing/expiry_date.rb +34 -0
  16. data/lib/active_merchant/billing/gateway.rb +170 -0
  17. data/lib/active_merchant/billing/gateways.rb +18 -0
  18. data/lib/active_merchant/billing/gateways/authorize_net.rb +664 -0
  19. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +858 -0
  20. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +308 -0
  21. data/lib/active_merchant/billing/gateways/beanstream.rb +139 -0
  22. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +282 -0
  23. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  24. data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
  25. data/lib/active_merchant/billing/gateways/bogus.rb +132 -0
  26. data/lib/active_merchant/billing/gateways/braintree.rb +17 -0
  27. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  28. data/lib/active_merchant/billing/gateways/braintree_blue.rb +293 -0
  29. data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -0
  30. data/lib/active_merchant/billing/gateways/braspag.rb +188 -0
  31. data/lib/active_merchant/billing/gateways/card_stream.rb +230 -0
  32. data/lib/active_merchant/billing/gateways/cyber_source.rb +430 -0
  33. data/lib/active_merchant/billing/gateways/data_cash.rb +597 -0
  34. data/lib/active_merchant/billing/gateways/efsnet.rb +235 -0
  35. data/lib/active_merchant/billing/gateways/elavon.rb +134 -0
  36. data/lib/active_merchant/billing/gateways/epay.rb +268 -0
  37. data/lib/active_merchant/billing/gateways/eway.rb +277 -0
  38. data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
  39. data/lib/active_merchant/billing/gateways/exact.rb +222 -0
  40. data/lib/active_merchant/billing/gateways/federated_canada.rb +168 -0
  41. data/lib/active_merchant/billing/gateways/first_pay.rb +177 -0
  42. data/lib/active_merchant/billing/gateways/garanti.rb +262 -0
  43. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -0
  44. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  45. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  46. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +55 -0
  47. data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
  48. data/lib/active_merchant/billing/gateways/instapay.rb +164 -0
  49. data/lib/active_merchant/billing/gateways/iridium.rb +258 -0
  50. data/lib/active_merchant/billing/gateways/jetpay.rb +276 -0
  51. data/lib/active_merchant/billing/gateways/linkpoint.rb +454 -0
  52. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +156 -0
  53. data/lib/active_merchant/billing/gateways/merchant_ware.rb +289 -0
  54. data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
  55. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +220 -0
  56. data/lib/active_merchant/billing/gateways/moneris.rb +209 -0
  57. data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
  58. data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
  59. data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
  60. data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
  61. data/lib/active_merchant/billing/gateways/ogone.rb +292 -0
  62. data/lib/active_merchant/billing/gateways/orbital.rb +321 -0
  63. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
  64. data/lib/active_merchant/billing/gateways/pay_junction.rb +392 -0
  65. data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
  66. data/lib/active_merchant/billing/gateways/paybox_direct.rb +207 -0
  67. data/lib/active_merchant/billing/gateways/payflow.rb +253 -0
  68. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +207 -0
  69. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  70. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  71. data/lib/active_merchant/billing/gateways/payflow_express.rb +222 -0
  72. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  73. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  74. data/lib/active_merchant/billing/gateways/payment_express.rb +235 -0
  75. data/lib/active_merchant/billing/gateways/paypal.rb +121 -0
  76. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +351 -0
  77. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +49 -0
  78. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  79. data/lib/active_merchant/billing/gateways/paypal_express.rb +177 -0
  80. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +25 -0
  81. data/lib/active_merchant/billing/gateways/plugnpay.rb +298 -0
  82. data/lib/active_merchant/billing/gateways/psigate.rb +219 -0
  83. data/lib/active_merchant/billing/gateways/psl_card.rb +304 -0
  84. data/lib/active_merchant/billing/gateways/qbms.rb +295 -0
  85. data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
  86. data/lib/active_merchant/billing/gateways/quickpay.rb +218 -0
  87. data/lib/active_merchant/billing/gateways/realex.rb +311 -0
  88. data/lib/active_merchant/billing/gateways/sage.rb +146 -0
  89. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
  90. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +116 -0
  91. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  92. data/lib/active_merchant/billing/gateways/sage_pay.rb +320 -0
  93. data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
  94. data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
  95. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  96. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +193 -0
  97. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
  98. data/lib/active_merchant/billing/gateways/skip_jack.rb +453 -0
  99. data/lib/active_merchant/billing/gateways/smart_ps.rb +271 -0
  100. data/lib/active_merchant/billing/gateways/stripe.rb +212 -0
  101. data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
  102. data/lib/active_merchant/billing/gateways/transax.rb +25 -0
  103. data/lib/active_merchant/billing/gateways/trust_commerce.rb +423 -0
  104. data/lib/active_merchant/billing/gateways/usa_epay.rb +194 -0
  105. data/lib/active_merchant/billing/gateways/verifi.rb +233 -0
  106. data/lib/active_merchant/billing/gateways/viaklix.rb +189 -0
  107. data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
  108. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  109. data/lib/active_merchant/billing/integrations.rb +17 -0
  110. data/lib/active_merchant/billing/integrations/action_view_helper.rb +68 -0
  111. data/lib/active_merchant/billing/integrations/bogus.rb +23 -0
  112. data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
  113. data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
  114. data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
  115. data/lib/active_merchant/billing/integrations/chronopay.rb +23 -0
  116. data/lib/active_merchant/billing/integrations/chronopay/helper.rb +120 -0
  117. data/lib/active_merchant/billing/integrations/chronopay/notification.rb +158 -0
  118. data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
  119. data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
  120. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
  121. data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
  122. data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
  123. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
  124. data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
  125. data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
  126. data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
  127. data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
  128. data/lib/active_merchant/billing/integrations/e_payment_plans.rb +48 -0
  129. data/lib/active_merchant/billing/integrations/e_payment_plans/helper.rb +34 -0
  130. data/lib/active_merchant/billing/integrations/e_payment_plans/notification.rb +84 -0
  131. data/lib/active_merchant/billing/integrations/gestpay.rb +25 -0
  132. data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
  133. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
  134. data/lib/active_merchant/billing/integrations/gestpay/notification.rb +85 -0
  135. data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
  136. data/lib/active_merchant/billing/integrations/helper.rb +96 -0
  137. data/lib/active_merchant/billing/integrations/hi_trust.rb +27 -0
  138. data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
  139. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
  140. data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
  141. data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
  142. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
  143. data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
  144. data/lib/active_merchant/billing/integrations/nochex.rb +88 -0
  145. data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
  146. data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
  147. data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
  148. data/lib/active_merchant/billing/integrations/notification.rb +62 -0
  149. data/lib/active_merchant/billing/integrations/paypal.rb +39 -0
  150. data/lib/active_merchant/billing/integrations/paypal/helper.rb +119 -0
  151. data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
  152. data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
  153. data/lib/active_merchant/billing/integrations/quickpay.rb +21 -0
  154. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
  155. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
  156. data/lib/active_merchant/billing/integrations/return.rb +42 -0
  157. data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
  158. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
  159. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +111 -0
  160. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
  161. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
  162. data/lib/active_merchant/billing/integrations/two_checkout.rb +23 -0
  163. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
  164. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
  165. data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
  166. data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
  167. data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
  168. data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
  169. data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +97 -0
  170. data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
  171. data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
  172. data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
  173. data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
  174. data/lib/active_merchant/billing/response.rb +32 -0
  175. data/lib/active_merchant/common.rb +14 -0
  176. data/lib/active_merchant/common/connection.rb +177 -0
  177. data/lib/active_merchant/common/country.rb +328 -0
  178. data/lib/active_merchant/common/error.rb +26 -0
  179. data/lib/active_merchant/common/post_data.rb +24 -0
  180. data/lib/active_merchant/common/posts_data.rb +63 -0
  181. data/lib/active_merchant/common/requires_parameters.rb +16 -0
  182. data/lib/active_merchant/common/utils.rb +22 -0
  183. data/lib/active_merchant/common/validateable.rb +81 -0
  184. data/lib/active_merchant/version.rb +3 -0
  185. data/lib/activemerchant.rb +1 -0
  186. data/lib/certs/cacert.pem +7815 -0
  187. data/lib/support/gateway_support.rb +58 -0
  188. data/lib/support/outbound_hosts.rb +25 -0
  189. metadata +276 -0
@@ -0,0 +1,74 @@
1
+ require 'net/http'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ module Integrations #:nodoc:
6
+ module Quickpay
7
+ class Notification < ActiveMerchant::Billing::Integrations::Notification
8
+ def complete?
9
+ status == '000'
10
+ end
11
+
12
+ def item_id
13
+ params['ordernumber']
14
+ end
15
+
16
+ def transaction_id
17
+ params['transaction']
18
+ end
19
+
20
+ def received_at
21
+ Time.parse("20#{params['time']}")
22
+ end
23
+
24
+ def gross
25
+ "%.2f" % (gross_cents / 100.0)
26
+ end
27
+
28
+ def gross_cents
29
+ params['amount'].to_i
30
+ end
31
+
32
+ def test?
33
+ params['testmode'] == 'Yes'
34
+ end
35
+
36
+ def status
37
+ params['qpstat']
38
+ end
39
+
40
+ def currency
41
+ params['currency']
42
+ end
43
+
44
+ # Provide access to raw fields from quickpay
45
+ %w(msgtype ordernumber state chstat chstatmsg qpstat qpstatmsg merchant merchantemail cardtype cardnumber).each do |attr|
46
+ define_method(attr) do
47
+ params[attr]
48
+ end
49
+ end
50
+
51
+ MD5_CHECK_FIELDS = [
52
+ :msgtype, :ordernumber, :amount, :currency, :time, :state,
53
+ :chstat, :chstatmsg, :qpstat, :qpstatmsg, :merchant, :merchantemail,
54
+ :transaction, :cardtype, :cardnumber, :testmode
55
+ ]
56
+
57
+ def generate_md5string
58
+ MD5_CHECK_FIELDS.map { |key| params[key.to_s] } * "" + @options[:credential2]
59
+ end
60
+
61
+ def generate_md5check
62
+ Digest::MD5.hexdigest(generate_md5string)
63
+ end
64
+
65
+ # Quickpay doesn't do acknowledgements of callback notifications
66
+ # Instead it uses and MD5 hash of all parameters
67
+ def acknowledge
68
+ generate_md5check == params['md5check']
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,42 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ class Return
5
+ attr_accessor :params
6
+ attr_reader :notification
7
+
8
+ def initialize(query_string, options = {})
9
+ @params = parse(query_string)
10
+ @options = options
11
+ end
12
+
13
+ # Successful by default. Overridden in the child class
14
+ def success?
15
+ true
16
+ end
17
+
18
+ # Not cancelled by default. Overridden in the child class.
19
+ def cancelled?
20
+ false
21
+ end
22
+
23
+ def message
24
+
25
+ end
26
+
27
+ def parse(query_string)
28
+ return {} if query_string.blank?
29
+
30
+ query_string.split('&').inject({}) do |memo, chunk|
31
+ next if chunk.empty?
32
+ key, value = chunk.split('=', 2)
33
+ next if key.empty?
34
+ value = value.nil? ? nil : CGI.unescape(value)
35
+ memo[CGI.unescape(key)] = value
36
+ memo
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module SagePayForm
5
+ autoload :Helper, File.dirname(__FILE__) + '/sage_pay_form/helper.rb'
6
+ autoload :Return, File.dirname(__FILE__) + '/sage_pay_form/return.rb'
7
+ autoload :Notification, File.dirname(__FILE__) + '/sage_pay_form/notification.rb'
8
+ autoload :Encryption, File.dirname(__FILE__) + '/sage_pay_form/encryption.rb'
9
+
10
+ mattr_accessor :production_url
11
+ mattr_accessor :test_url
12
+ mattr_accessor :simulate_url
13
+ self.production_url = 'https://live.sagepay.com/gateway/service/vspform-register.vsp'
14
+ self.test_url = 'https://test.sagepay.com/gateway/service/vspform-register.vsp'
15
+ self.simulate_url = 'https://test.sagepay.com/Simulator/VSPFormGateway.asp'
16
+
17
+ def self.return(query_string, options = {})
18
+ Return.new(query_string, options)
19
+ end
20
+
21
+ def self.service_url
22
+ mode = ActiveMerchant::Billing::Base.integration_mode
23
+ case mode
24
+ when :production
25
+ self.production_url
26
+ when :test
27
+ self.test_url
28
+ when :simulate
29
+ self.simulate_url
30
+ else
31
+ raise StandardError, "Integration mode set to an invalid value: #{mode}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module SagePayForm
5
+ module Encryption
6
+ def sage_encrypt(plaintext, key)
7
+ ActiveSupport::Base64.encode64s(sage_encrypt_xor(plaintext, key))
8
+ end
9
+
10
+ def sage_decrypt(ciphertext, key)
11
+ sage_encrypt_xor(ActiveSupport::Base64.decode64(ciphertext), key)
12
+ end
13
+
14
+ def sage_encrypt_salt(min, max)
15
+ length = rand(max - min + 1) + min
16
+ SecureRandom.base64(length + 4)[0, length]
17
+ end
18
+
19
+ private
20
+
21
+ def sage_encrypt_xor(data, key)
22
+ raise 'No key provided' if key.blank?
23
+
24
+ key *= (data.length.to_f / key.length.to_f).ceil
25
+ key = key[0, data.length]
26
+
27
+ data.bytes.zip(key.bytes).map { |b1, b2| (b1 ^ b2).chr }.join
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,111 @@
1
+ require 'uri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ module Integrations #:nodoc:
6
+ module SagePayForm
7
+ class Helper < ActiveMerchant::Billing::Integrations::Helper
8
+ include Encryption
9
+
10
+ mapping :credential2, 'EncryptKey'
11
+
12
+ mapping :account, 'Vendor'
13
+ mapping :amount, 'Amount'
14
+ mapping :currency, 'Currency'
15
+
16
+ mapping :order, 'VendorTxCode'
17
+
18
+ mapping :customer,
19
+ :first_name => 'BillingFirstnames',
20
+ :last_name => 'BillingSurname',
21
+ :email => 'CustomerEMail',
22
+ :phone => 'BillingPhone',
23
+ :send_email_confirmation => 'SendEmail'
24
+
25
+ mapping :billing_address,
26
+ :city => 'BillingCity',
27
+ :address1 => 'BillingAddress1',
28
+ :address2 => 'BillingAddress2',
29
+ :state => 'BillingState',
30
+ :zip => 'BillingPostCode',
31
+ :country => 'BillingCountry'
32
+
33
+ mapping :shipping_address,
34
+ :city => 'DeliveryCity',
35
+ :address1 => 'DeliveryAddress1',
36
+ :address2 => 'DeliveryAddress2',
37
+ :state => 'DeliveryState',
38
+ :zip => 'DeliveryPostCode',
39
+ :country => 'DeliveryCountry'
40
+
41
+ mapping :return_url, 'SuccessURL'
42
+ mapping :description, 'Description'
43
+
44
+ def form_fields
45
+ fields['DeliveryFirstnames'] ||= fields['BillingFirstnames']
46
+ fields['DeliverySurname'] ||= fields['BillingSurname']
47
+
48
+ fields['FailureURL'] ||= fields['SuccessURL']
49
+
50
+ crypt_skip = ['Vendor', 'EncryptKey', 'SendEmail']
51
+ crypt_skip << 'BillingState' unless fields['BillingCountry'] == 'US'
52
+ crypt_skip << 'DeliveryState' unless fields['DeliveryCountry'] == 'US'
53
+ crypt_skip << 'CustomerEMail' unless fields['SendEmail']
54
+
55
+ key = fields['EncryptKey']
56
+ @crypt ||= create_crypt_field(fields.except(*crypt_skip), key)
57
+
58
+ {
59
+ 'VPSProtocol' => '2.23',
60
+ 'TxType' => 'PAYMENT',
61
+ 'Vendor' => @fields['Vendor'],
62
+ 'Crypt' => @crypt
63
+ }
64
+ end
65
+
66
+ private
67
+
68
+ def create_crypt_field(fields, key)
69
+ parts = fields.map { |k, v| "#{k}=#{sanitize(k, v)}" unless v.nil? }.compact.shuffle
70
+ parts.unshift(sage_encrypt_salt(key.length, key.length * 2))
71
+ sage_encrypt(parts.join('&'), key)
72
+ end
73
+
74
+ def sanitize(key, value)
75
+ reject = exact = nil
76
+
77
+ case key
78
+ when /URL$/
79
+ # allow all
80
+ when 'VendorTxCode'
81
+ reject = /[^A-Za-z0-9{}._-]+/
82
+ when /[Nn]ames?$/
83
+ reject = %r{[^[:alpha:] /\\.'-]+}
84
+ when /(?:Address[12]|City)$/
85
+ reject = %r{[^[:alnum:] +'/\\:,.\n()-]+}
86
+ when /PostCode$/
87
+ reject = /[^A-Za-z0-9 -]+/
88
+ when /Phone$/
89
+ reject = /[^0-9A-Za-z+ ()-]+/
90
+ when 'Currency'
91
+ exact = /^[A-Z]{3}$/
92
+ when /State$/
93
+ exact = /^[A-Z]{2}$/
94
+ else
95
+ reject = /&+/
96
+ end
97
+
98
+ if exact
99
+ raise ArgumentError, "Invalid value for #{key}: #{value.inspect}" unless value =~ exact
100
+ value
101
+ elsif reject
102
+ value.gsub(reject, ' ')
103
+ else
104
+ value
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,210 @@
1
+ require 'net/http'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ module Integrations #:nodoc:
6
+ module SagePayForm
7
+ class Notification < ActiveMerchant::Billing::Integrations::Notification
8
+ class CryptError < StandardError; end
9
+
10
+ include Encryption
11
+
12
+ def initialize(post_data, options)
13
+ super
14
+ load_crypt_params(params['crypt'], options[:credential2])
15
+ end
16
+
17
+ # Was the transaction complete?
18
+ def complete?
19
+ status_code == 'OK'
20
+ end
21
+
22
+ # Was the transaction cancelled?
23
+ # Unfortunately, we can't distinguish "user abort" from "idle too long".
24
+ def cancelled?
25
+ status_code == 'ABORT'
26
+ end
27
+
28
+ # Text version of #complete?, since we don't support Pending.
29
+ def status
30
+ complete? ? 'Completed' : 'Failed'
31
+ end
32
+
33
+ # Status of transaction. List of possible values:
34
+ # <tt>OK</tt>:: Transaction completed successfully.
35
+ # <tt>NOTAUTHED</tt>:: Incorrect card details / insufficient funds.
36
+ # <tt>MALFORMED</tt>:: Invalid input data.
37
+ # <tt>INVALID</tt>:: Valid input data, but some fields are incorrect.
38
+ # <tt>ABORT</tt>:: User hit cancel button or went idle for 15+ minutes.
39
+ # <tt>REJECTED</tt>:: Rejected by account fraud screening rules.
40
+ # <tt>AUTHENTICATED</tt>:: Authenticated card details secured at SagePay.
41
+ # <tt>REGISTERED</tt>:: Non-authenticated card details secured at SagePay.
42
+ # <tt>ERROR</tt>:: Problem internal to SagePay.
43
+ def status_code
44
+ params['Status']
45
+ end
46
+
47
+ # Check this if #completed? is false.
48
+ def message
49
+ params['StatusDetail']
50
+ end
51
+
52
+ # Vendor-supplied code (:order mapping).
53
+ def item_id
54
+ params['VendorTxCode']
55
+ end
56
+
57
+ # Internal SagePay code, typically "{LONG-UUID}".
58
+ def transaction_id
59
+ params['VPSTxId']
60
+ end
61
+
62
+ # Authorization number (only if #completed?).
63
+ def auth_id
64
+ params['TxAuthNo']
65
+ end
66
+
67
+ # Total amount (no fees).
68
+ def gross
69
+ params['Amount']
70
+ end
71
+
72
+ # AVS and CV2 check results. Possible values:
73
+ # <tt>ALL MATCH</tt>::
74
+ # <tt>SECURITY CODE MATCH ONLY</tt>::
75
+ # <tt>ADDRESS MATCH ONLY</tt>::
76
+ # <tt>NO DATA MATCHES</tt>::
77
+ # <tt>DATA NOT CHECKED</tt>::
78
+ def avs_cv2_result
79
+ params['AVSCV2']
80
+ end
81
+
82
+ # Numeric address check. Possible values:
83
+ # <tt>NOTPROVIDED</tt>::
84
+ # <tt>NOTCHECKED</tt>::
85
+ # <tt>MATCHED</tt>::
86
+ # <tt>NOTMATCHED</tt>::
87
+ def address_result
88
+ params['AddressResult']
89
+ end
90
+
91
+ # Post code check. Possible values:
92
+ # <tt>NOTPROVIDED</tt>::
93
+ # <tt>NOTCHECKED</tt>::
94
+ # <tt>MATCHED</tt>::
95
+ # <tt>NOTMATCHED</tt>::
96
+ def post_code_result
97
+ params['PostCodeResult']
98
+ end
99
+
100
+ # CV2 code check. Possible values:
101
+ # <tt>NOTPROVIDED</tt>::
102
+ # <tt>NOTCHECKED</tt>::
103
+ # <tt>MATCHED</tt>::
104
+ # <tt>NOTMATCHED</tt>::
105
+ def cv2_result
106
+ params['CV2Result']
107
+ end
108
+
109
+ # Was the Gift Aid box checked?
110
+ def gift_aid?
111
+ params['GiftAid'] == '1'
112
+ end
113
+
114
+ # Result of 3D Secure checks. Possible values:
115
+ # <tt>OK</tt>:: Authenticated correctly.
116
+ # <tt>NOTCHECKED</tt>:: Authentication not performed.
117
+ # <tt>NOTAVAILABLE</tt>:: Card not auth-capable, or auth is otherwise impossible.
118
+ # <tt>NOTAUTHED</tt>:: User failed authentication.
119
+ # <tt>INCOMPLETE</tt>:: Authentication unable to complete.
120
+ # <tt>ERROR</tt>:: Unable to attempt authentication due to data / service errors.
121
+ def buyer_auth_result
122
+ params['3DSecureStatus']
123
+ end
124
+
125
+ # Encoded 3D Secure result code.
126
+ def buyer_auth_result_code
127
+ params['CAVV']
128
+ end
129
+
130
+ # Address confirmation status. PayPal only. Possible values:
131
+ # <tt>NONE</tt>::
132
+ # <tt>CONFIRMED</tt>::
133
+ # <tt>UNCONFIRMED</tt>::
134
+ def address_status
135
+ params['AddressStatus']
136
+ end
137
+
138
+ # Payer verification. Undocumented.
139
+ def payer_verified?
140
+ params['PayerStatus'] == 'VERIFIED'
141
+ end
142
+
143
+ # Credit card type. Possible values:
144
+ # <tt>VISA</tt>:: Visa
145
+ # <tt>MC</tt>:: MasterCard
146
+ # <tt>DELTA</tt>:: Delta
147
+ # <tt>SOLO</tt>:: Solo
148
+ # <tt>MAESTRO</tt>:: Maestro (UK and International)
149
+ # <tt>UKE</tt>:: Visa Electron
150
+ # <tt>AMEX</tt>:: American Express
151
+ # <tt>DC</tt>:: Diners Club
152
+ # <tt>JCB</tt>:: JCB
153
+ # <tt>LASER</tt>:: Laser
154
+ # <tt>PAYPAL</tt>:: PayPal
155
+ def credit_card_type
156
+ params['CardType']
157
+ end
158
+
159
+ # Last four digits of credit card.
160
+ def credit_card_last_4_digits
161
+ params['Last4Digits']
162
+ end
163
+
164
+ # Used by composition methods, but not supplied by SagePay.
165
+ def currency
166
+ nil
167
+ end
168
+
169
+ def test?
170
+ false
171
+ end
172
+
173
+ def acknowledge
174
+ true
175
+ end
176
+
177
+ private
178
+
179
+ def load_crypt_params(crypt, key)
180
+ raise MissingCryptData if crypt.blank?
181
+ raise MissingCryptKey if key.blank?
182
+
183
+ crypt_data = sage_decrypt(crypt.gsub(' ', '+'), key)
184
+ raise InvalidCryptData unless crypt_data =~ /(^|&)Status=/
185
+
186
+ params.clear
187
+ parse(crypt_data)
188
+ end
189
+
190
+ class MissingCryptKey < CryptError
191
+ def message
192
+ 'No merchant decryption key supplied'
193
+ end
194
+ end
195
+ class MissingCryptData < CryptError
196
+ def message
197
+ 'No data received from SagePay'
198
+ end
199
+ end
200
+ class InvalidCryptData < CryptError
201
+ def message
202
+ 'Invalid data received from SagePay'
203
+ end
204
+ end
205
+
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end