activemerchant 1.1.0 → 1.2.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 (178) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +226 -0
  3. data/CONTRIBUTERS +52 -0
  4. data/README +34 -24
  5. data/Rakefile +152 -0
  6. data/gem-public_cert.pem +20 -0
  7. data/init.rb +3 -0
  8. data/lib/active_merchant.rb +3 -1
  9. data/lib/active_merchant/billing/credit_card.rb +21 -17
  10. data/lib/active_merchant/billing/credit_card_methods.rb +17 -19
  11. data/lib/active_merchant/billing/gateway.rb +160 -44
  12. data/lib/active_merchant/billing/gateways.rb +2 -15
  13. data/lib/active_merchant/billing/gateways/authorize_net.rb +21 -21
  14. data/lib/active_merchant/billing/gateways/bogus.rb +6 -6
  15. data/lib/active_merchant/billing/gateways/brain_tree.rb +191 -0
  16. data/lib/active_merchant/billing/gateways/card_stream.rb +207 -0
  17. data/lib/active_merchant/billing/gateways/cyber_source.rb +402 -0
  18. data/lib/active_merchant/billing/gateways/data_cash.rb +41 -97
  19. data/lib/active_merchant/billing/gateways/efsnet.rb +256 -0
  20. data/lib/active_merchant/billing/gateways/eway.rb +77 -29
  21. data/lib/active_merchant/billing/gateways/exact.rb +230 -0
  22. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -33
  23. data/lib/active_merchant/billing/gateways/moneris.rb +155 -125
  24. data/lib/active_merchant/billing/gateways/net_registry.rb +257 -0
  25. data/lib/active_merchant/billing/gateways/pay_junction.rb +407 -0
  26. data/lib/active_merchant/billing/gateways/payflow.rb +163 -25
  27. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +56 -38
  28. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +10 -1
  29. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +9 -0
  30. data/lib/active_merchant/billing/gateways/payflow_express.rb +36 -11
  31. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +6 -0
  32. data/lib/active_merchant/billing/gateways/payflow_uk.rb +7 -3
  33. data/lib/active_merchant/billing/gateways/payment_express.rb +261 -0
  34. data/lib/active_merchant/billing/gateways/paypal.rb +18 -4
  35. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +31 -15
  36. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +8 -0
  37. data/lib/active_merchant/billing/gateways/paypal_express.rb +33 -8
  38. data/lib/active_merchant/billing/gateways/plugnpay.rb +300 -0
  39. data/lib/active_merchant/billing/gateways/protx.rb +285 -0
  40. data/lib/active_merchant/billing/gateways/psigate.rb +13 -12
  41. data/lib/active_merchant/billing/gateways/psl_card.rb +297 -0
  42. data/lib/active_merchant/billing/gateways/quickpay.rb +197 -0
  43. data/lib/active_merchant/billing/gateways/realex.rb +212 -0
  44. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  45. data/lib/active_merchant/billing/gateways/trans_first.rb +136 -0
  46. data/lib/active_merchant/billing/gateways/trust_commerce.rb +43 -20
  47. data/lib/active_merchant/billing/gateways/usa_epay.rb +6 -5
  48. data/lib/active_merchant/billing/gateways/verifi.rb +235 -0
  49. data/lib/active_merchant/billing/gateways/viaklix.rb +171 -0
  50. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +0 -2
  51. data/lib/active_merchant/billing/integrations/helper.rb +8 -1
  52. data/lib/active_merchant/billing/integrations/nochex.rb +62 -1
  53. data/lib/active_merchant/billing/integrations/nochex/notification.rb +9 -16
  54. data/lib/active_merchant/billing/integrations/notification.rb +1 -1
  55. data/lib/active_merchant/billing/integrations/paypal/helper.rb +59 -46
  56. data/lib/active_merchant/billing/integrations/paypal/notification.rb +14 -47
  57. data/lib/active_merchant/lib/error.rb +4 -0
  58. data/lib/active_merchant/lib/post_data.rb +22 -0
  59. data/lib/active_merchant/lib/posts_data.rb +23 -5
  60. data/lib/active_merchant/lib/requires_parameters.rb +2 -2
  61. data/lib/active_merchant/lib/validateable.rb +1 -1
  62. data/lib/support/gateway_support.rb +45 -0
  63. data/lib/tasks/cia.rb +1 -1
  64. data/script/generate +14 -0
  65. data/script/generator/base.rb +45 -0
  66. data/script/generator/generator.rb +24 -0
  67. data/script/generator/generators/gateway/gateway_generator.rb +14 -0
  68. data/script/generator/generators/gateway/templates/gateway.rb +73 -0
  69. data/script/generator/generators/gateway/templates/gateway_test.rb +41 -0
  70. data/script/generator/generators/gateway/templates/remote_gateway_test.rb +56 -0
  71. data/script/generator/generators/integration/integration_generator.rb +25 -0
  72. data/script/generator/generators/integration/templates/helper.rb +34 -0
  73. data/script/generator/generators/integration/templates/helper_test.rb +54 -0
  74. data/script/generator/generators/integration/templates/integration.rb +18 -0
  75. data/script/generator/generators/integration/templates/module_test.rb +9 -0
  76. data/script/generator/generators/integration/templates/notification.rb +100 -0
  77. data/script/generator/generators/integration/templates/notification_test.rb +41 -0
  78. data/script/generator/manifest.rb +20 -0
  79. data/test/extra/binding_of_caller.rb +80 -0
  80. data/test/extra/breakpoint.rb +547 -0
  81. data/test/fixtures.yml +251 -0
  82. data/test/remote_tests/remote_authorize_net_test.rb +113 -0
  83. data/test/remote_tests/remote_brain_tree_test.rb +78 -0
  84. data/test/remote_tests/remote_card_stream_test.rb +160 -0
  85. data/test/remote_tests/remote_cyber_source_test.rb +130 -0
  86. data/test/remote_tests/remote_data_cash_test.rb +155 -0
  87. data/test/remote_tests/remote_efsnet_test.rb +93 -0
  88. data/test/remote_tests/remote_eway_test.rb +71 -0
  89. data/test/remote_tests/remote_exact_test.rb +59 -0
  90. data/test/remote_tests/remote_gestpay_integration_test.rb +37 -0
  91. data/test/remote_tests/remote_linkpoint_test.rb +144 -0
  92. data/test/remote_tests/remote_moneris_test.rb +110 -0
  93. data/test/remote_tests/remote_net_registry_test.rb +120 -0
  94. data/test/remote_tests/remote_pay_junction_test.rb +162 -0
  95. data/test/remote_tests/remote_payflow_express_test.rb +50 -0
  96. data/test/remote_tests/remote_payflow_test.rb +241 -0
  97. data/test/remote_tests/remote_payflow_uk_test.rb +172 -0
  98. data/test/remote_tests/remote_payment_express_test.rb +136 -0
  99. data/test/remote_tests/remote_paypal_express_test.rb +49 -0
  100. data/test/remote_tests/remote_paypal_integration_test.rb +14 -0
  101. data/test/remote_tests/remote_paypal_test.rb +163 -0
  102. data/test/remote_tests/remote_plugnpay_test.rb +70 -0
  103. data/test/remote_tests/remote_protx_test.rb +184 -0
  104. data/test/remote_tests/remote_psigate_test.rb +87 -0
  105. data/test/remote_tests/remote_psl_card_test.rb +105 -0
  106. data/test/remote_tests/remote_quickpay_test.rb +182 -0
  107. data/test/remote_tests/remote_realex_test.rb +227 -0
  108. data/test/remote_tests/remote_secure_pay_test.rb +36 -0
  109. data/test/remote_tests/remote_trans_first_test.rb +37 -0
  110. data/test/remote_tests/remote_trust_commerce_test.rb +136 -0
  111. data/test/remote_tests/remote_usa_epay_test.rb +57 -0
  112. data/test/remote_tests/remote_verifi_test.rb +107 -0
  113. data/test/remote_tests/remote_viaklix_test.rb +53 -0
  114. data/test/test_helper.rb +132 -0
  115. data/test/unit/base_test.rb +61 -0
  116. data/test/unit/country_code_test.rb +33 -0
  117. data/test/unit/country_test.rb +64 -0
  118. data/test/unit/credit_card_formatting_test.rb +24 -0
  119. data/test/unit/credit_card_methods_test.rb +37 -0
  120. data/test/unit/credit_card_test.rb +365 -0
  121. data/test/unit/gateways/authorize_net_test.rb +140 -0
  122. data/test/unit/gateways/bogus_test.rb +43 -0
  123. data/test/unit/gateways/brain_tree_test.rb +77 -0
  124. data/test/unit/gateways/card_stream_test.rb +37 -0
  125. data/test/unit/gateways/cyber_source_test.rb +151 -0
  126. data/test/unit/gateways/data_cash_test.rb +23 -0
  127. data/test/unit/gateways/efsnet_test.rb +70 -0
  128. data/test/unit/gateways/eway_test.rb +105 -0
  129. data/test/unit/gateways/exact_test.rb +118 -0
  130. data/test/unit/gateways/gateway_test.rb +24 -0
  131. data/test/unit/gateways/linkpoint_test.rb +165 -0
  132. data/test/unit/gateways/moneris_test.rb +167 -0
  133. data/test/unit/gateways/net_registry_test.rb +478 -0
  134. data/test/unit/gateways/pay_junction_test.rb +61 -0
  135. data/test/unit/gateways/payflow_express_test.rb +165 -0
  136. data/test/unit/gateways/payflow_express_uk_test.rb +14 -0
  137. data/test/unit/gateways/payflow_test.rb +230 -0
  138. data/test/unit/gateways/payflow_uk_test.rb +68 -0
  139. data/test/unit/gateways/payment_express_test.rb +215 -0
  140. data/test/unit/gateways/paypal_express_test.rb +222 -0
  141. data/test/unit/gateways/paypal_test.rb +241 -0
  142. data/test/unit/gateways/plugnpay_test.rb +79 -0
  143. data/test/unit/gateways/protx_test.rb +110 -0
  144. data/test/unit/gateways/psigate_test.rb +110 -0
  145. data/test/unit/gateways/psl_card_test.rb +51 -0
  146. data/test/unit/gateways/quickpay_test.rb +125 -0
  147. data/test/unit/gateways/realex_test.rb +150 -0
  148. data/test/unit/gateways/secure_pay_test.rb +78 -0
  149. data/test/unit/gateways/trans_first_test.rb +125 -0
  150. data/test/unit/gateways/trust_commerce_test.rb +57 -0
  151. data/test/unit/gateways/usa_epay_test.rb +117 -0
  152. data/test/unit/gateways/verifi_test.rb +91 -0
  153. data/test/unit/gateways/viaklix_test.rb +72 -0
  154. data/test/unit/integrations/action_view_helper_test.rb +54 -0
  155. data/test/unit/integrations/bogus_module_test.rb +16 -0
  156. data/test/unit/integrations/chronopay_module_test.rb +9 -0
  157. data/test/unit/integrations/gestpay_module_test.rb +10 -0
  158. data/test/unit/integrations/helpers/bogus_helper_test.rb +28 -0
  159. data/test/unit/integrations/helpers/chronopay_helper_test.rb +67 -0
  160. data/test/unit/integrations/helpers/gestpay_helper_test.rb +100 -0
  161. data/test/unit/integrations/helpers/nochex_helper_test.rb +53 -0
  162. data/test/unit/integrations/helpers/paypal_helper_test.rb +162 -0
  163. data/test/unit/integrations/helpers/two_checkout_helper_test.rb +92 -0
  164. data/test/unit/integrations/nochex_module_test.rb +9 -0
  165. data/test/unit/integrations/notifications/chronopay_notification_test.rb +66 -0
  166. data/test/unit/integrations/notifications/gestpay_notification_test.rb +60 -0
  167. data/test/unit/integrations/notifications/nochex_notification_test.rb +51 -0
  168. data/test/unit/integrations/notifications/notification_test.rb +41 -0
  169. data/test/unit/integrations/notifications/paypal_notification_test.rb +85 -0
  170. data/test/unit/integrations/notifications/two_checkout_notification_test.rb +55 -0
  171. data/test/unit/integrations/paypal_module_test.rb +24 -0
  172. data/test/unit/integrations/two_checkout_module_test.rb +9 -0
  173. data/test/unit/post_data_test.rb +55 -0
  174. data/test/unit/response_test.rb +14 -0
  175. data/test/unit/validateable_test.rb +56 -0
  176. metadata +160 -7
  177. metadata.gz.sig +0 -0
  178. data/lib/active_merchant/billing/gateways/payflow/f73e89fd.0 +0 -17
@@ -30,8 +30,6 @@ module ActiveMerchant #:nodoc:
30
30
  :expiry_year => 'PAY1_EXPYEAR',
31
31
  :verification_value => 'PAY1_CVV'
32
32
 
33
- mapping :billing_address, {}
34
-
35
33
  def customer(params = {})
36
34
  add_field(mappings[:customer][:email], params[:email])
37
35
  add_field('PAY1_CHNAME', "#{params[:first_name]} #{params[:last_name]}")
@@ -7,6 +7,11 @@ module ActiveMerchant #:nodoc:
7
7
  class_inheritable_hash :mappings
8
8
  class_inheritable_accessor :country_format
9
9
  self.country_format = :alpha2
10
+
11
+ # The application making the calls to the gateway
12
+ # Useful for things like the PayPal build notation (BN) id fields
13
+ class_inheritable_accessor :application_id
14
+ self.application_id = 'ActiveMerchant'
10
15
 
11
16
  def initialize(order, account, options = {})
12
17
  options.assert_valid_keys([:amount, :currency, :test])
@@ -49,8 +54,10 @@ module ActiveMerchant #:nodoc:
49
54
  private
50
55
 
51
56
  def add_address(key, params)
57
+ return if mappings[key].nil?
58
+
52
59
  code = lookup_country_code(params.delete(:country))
53
- add_field(mappings[key][:country], code) if mappings[key]
60
+ add_field(mappings[key][:country], code)
54
61
  add_fields(key, params)
55
62
  end
56
63
 
@@ -4,6 +4,65 @@ require File.dirname(__FILE__) + '/nochex/notification.rb'
4
4
  module ActiveMerchant #:nodoc:
5
5
  module Billing #:nodoc:
6
6
  module Integrations #:nodoc:
7
+ # To start with Nochex, follow the instructions for installing
8
+ # ActiveMerchant as a plugin, as described on
9
+ # http://www.activemerchant.org/.
10
+ #
11
+ # The plugin will automatically add the ActionView helper for
12
+ # ActiveMerchant, which will allow you to make the Nochex payments.
13
+ # The idea behind the helper is that it generates an invisible
14
+ # forwarding screen that will automatically redirect the user.
15
+ # So you would collect all the information about the order and then
16
+ # simply render the hidden form, which redirects the user to Nochex.
17
+ #
18
+ # The syntax of the helper is as follows:
19
+ #
20
+ # <% payment_service_for 'order id', 'nochex_user_id',
21
+ # :amount => 50.00,
22
+ # :service => :nochex,
23
+ # :html => { :id => 'nochex-form' } do |service| %>
24
+ #
25
+ # <% service.customer :first_name => 'Cody',
26
+ # :last_name => 'Fauser',
27
+ # :phone => '(555)555-5555',
28
+ # :email => 'cody@example.com' %>
29
+ #
30
+ # <% service.billing_address :city => 'Ottawa',
31
+ # :address1 => '21 Snowy Brook Lane',
32
+ # :address2 => 'Apt. 36',
33
+ # :state => 'ON',
34
+ # :country => 'CA',
35
+ # :zip => 'K1J1E5' %>
36
+ #
37
+ # <% service.invoice '#1000' %>
38
+ # <% service.shipping '0.00' %>
39
+ # <% service.tax '0.00' %>
40
+ #
41
+ # <% service.notify_url url_for(:action => 'notify', :only_path => false) %>
42
+ # <% service.return_url url_for(:action => 'done', :only_path => false) %>
43
+ # <% service.cancel_return_url 'http://mystore.com' %>
44
+ # <% end %>
45
+ #
46
+ # The notify_url is the URL that the Nochex IPN will be sent. You can
47
+ # handle the notification in your controller action as follows:
48
+ #
49
+ # class NotificationController < ApplicationController
50
+ # include ActiveMerchant::Billing::Integrations
51
+ #
52
+ # def notify
53
+ # notification = Nochex::Notification.new(request.raw_post)
54
+ #
55
+ # begin
56
+ # # Acknowledge notification with Nochex
57
+ # raise StandardError, 'Illegal Notification' unless notification.acknowledge
58
+ # # Process the payment
59
+ # rescue => e
60
+ # logger.warn("Illegal notification received: #{e.message}")
61
+ # ensure
62
+ # head(:ok)
63
+ # end
64
+ # end
65
+ # end
7
66
  module Nochex
8
67
 
9
68
  mattr_accessor :service_url
@@ -12,10 +71,12 @@ module ActiveMerchant #:nodoc:
12
71
  mattr_accessor :notification_confirmation_url
13
72
  self.notification_confirmation_url = 'https://www.nochex.com/nochex.dll/apc/apc'
14
73
 
74
+ # Simply a convenience method that returns a new
75
+ # ActiveMerchant::Billing::Integrations::Nochex::Notification
15
76
  def self.notification(post)
16
77
  Notification.new(post)
17
78
  end
18
79
  end
19
80
  end
20
81
  end
21
- end
82
+ end
@@ -74,25 +74,18 @@ module ActiveMerchant #:nodoc:
74
74
  # else
75
75
  # ... log possible hacking attempt ...
76
76
  # end
77
- def acknowledge
78
- payload = raw
77
+ def acknowledge
78
+ payload = raw
79
79
 
80
- uri = URI.parse(Nochex.notification_confirmation_url)
80
+ response = ssl_post(Nochex.notification_confirmation_url, payload,
81
+ 'Content-Length' => "#{payload.size}",
82
+ 'User-Agent' => "Active Merchant -- http://activemerchant.org",
83
+ 'Content-Type' => "application/x-www-form-urlencoded"
84
+ )
81
85
 
82
- request = Net::HTTP::Post.new(uri.path)
86
+ raise StandardError.new("Faulty Nochex result: #{response}") unless ["AUTHORISED", "DECLINED"].include?(response)
83
87
 
84
- request['Content-Length'] = "#{payload.size}"
85
- request['User-Agent'] = "Active Merchant -- http://home.leetsoft.com/am"
86
- request['Content-Type'] = "application/x-www-form-urlencoded"
87
-
88
- http = Net::HTTP.new(uri.host, uri.port)
89
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @ssl_strict
90
- http.use_ssl = true
91
-
92
- response = http.request(request, payload)
93
-
94
- raise StandardError.new("Faulty Nochex result: #{response.body}") unless ["AUTHORISED", "DECLINED"].include?(response.body)
95
- response.body == "AUTHORISED"
88
+ response == "AUTHORISED"
96
89
  end
97
90
  end
98
91
  end
@@ -43,7 +43,7 @@ module ActiveMerchant #:nodoc:
43
43
  def parse(post)
44
44
  @raw = post.to_s
45
45
  for line in @raw.split('&')
46
- key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
46
+ key, value = *line.scan( %r{^([A-Za-z0-9_.]+)\=(.*)$} ).flatten
47
47
  params[key] = CGI.unescape(value)
48
48
  end
49
49
  end
@@ -29,7 +29,8 @@ module ActiveMerchant #:nodoc:
29
29
  add_field('no_shipping', '1')
30
30
  add_field('no_note', '1')
31
31
  add_field('charset', 'utf-8')
32
- add_field('address_override', '1')
32
+ add_field('address_override', '0')
33
+ add_field('bn', application_id.to_s.slice(0,32)) unless application_id.blank?
33
34
  end
34
35
 
35
36
  mapping :amount, 'amount'
@@ -45,57 +46,69 @@ module ActiveMerchant #:nodoc:
45
46
  mapping :no_note, 'no_note'
46
47
  mapping :address_override, 'address_override'
47
48
 
49
+ mapping :application_id, 'bn'
50
+
48
51
  mapping :customer, :first_name => 'first_name',
49
52
  :last_name => 'last_name',
50
- :email => 'email',
51
- :phone => 'night_phone_a'
53
+ :email => 'email'
52
54
 
53
- mapping :billing_address, :city => 'city',
54
- :address1 => 'address1',
55
- :address2 => 'address2',
56
- :state => 'state',
57
- :zip => 'zip',
58
- :country => 'country',
59
- :phone_a => "night_phone_a",
60
- :phone_b => "night_phone_b",
61
- :phone_c => "night_phone_c"
55
+ mapping :shipping_address, :city => 'city',
56
+ :address1 => 'address1',
57
+ :address2 => 'address2',
58
+ :state => 'state',
59
+ :zip => 'zip',
60
+ :country => 'country'
61
+
62
+ def shipping_address(params = {})
63
+
64
+ if params.has_key?(:phone)
65
+ phone = params.delete(:phone).to_s
66
+
67
+ # Whipe all non digits
68
+ phone.gsub!(/\D+/, '')
69
+
70
+ # Parse in the us style (555 555 5555) which seems to be the only format paypal supports. Ignore anything before this.
71
+ if phone =~ /(\d{3})(\d{3})(\d{4})$/
72
+ add_field('night_phone_a', $1)
73
+ add_field('night_phone_b', $2)
74
+ add_field('night_phone_c', $3)
75
+ end
76
+ end
77
+
78
+ # Get the country code in the correct format
79
+ # Use what we were given if we can't find anything
80
+ country_code = lookup_country_code(params.delete(:country))
81
+ add_field(mappings[:shipping_address][:country], country_code)
82
+
83
+ province_code = params.delete(:state)
84
+
85
+ case country_code
86
+ when 'CA'
87
+ add_field(mappings[:shipping_address][:state], CANADIAN_PROVINCES[province_code.upcase]) unless province_code.nil?
88
+ when 'US'
89
+ add_field(mappings[:shipping_address][:state], province_code)
90
+ else
91
+ add_field(mappings[:shipping_address][:state], province_code.blank? ? 'N/A' : province_code)
92
+ end
93
+
94
+ # Everything else
95
+ params.each do |k, v|
96
+ field = mappings[:shipping_address][k]
97
+ add_field(field, v) unless field.nil?
98
+ end
99
+ end
62
100
 
63
- def billing_address(params = {})
64
-
65
- if params.has_key?(:phone)
66
- phone = params.delete(:phone).to_s
67
-
68
- # Whipe all non digits
69
- phone.gsub!(/\D+/, '')
70
-
71
- # Parse in the us style (555 555 5555) which seems to be the only format paypal supports. Ignore anything before this.
72
- if phone =~ /(\d{3})(\d{3})(\d{4})$/
73
- add_field(mappings[:billing_address][:phone_a], $1)
74
- add_field(mappings[:billing_address][:phone_b], $2)
75
- add_field(mappings[:billing_address][:phone_c], $3)
76
- end
77
- end
78
-
79
- # Get the country code in the correct format
80
- # Use what we were given if we can't find anything
81
- country_code = lookup_country_code(params.delete(:country))
82
- add_field(mappings[:billing_address][:country], country_code)
83
- # Fix Canadian province if required
84
- if country_code == 'CA'
85
- province_code = params.delete(:state)
86
- add_field(mappings[:billing_address][:state], CANADIAN_PROVINCES[province_code.upcase]) unless province_code.nil?
87
- end
88
-
89
- # Everything else
90
- params.each do |k, v|
91
- field = mappings[:billing_address][k]
92
- add_field(field, v) unless field.nil?
93
- end
94
- end
95
-
96
-
97
101
  mapping :tax, 'tax'
98
102
  mapping :shipping, 'shipping'
103
+ mapping :cmd, 'cmd'
104
+ mapping :custom, 'custom'
105
+ mapping :src, 'src'
106
+ mapping :sra, 'sra'
107
+ %w(a p t).each do |l|
108
+ (1..3).each do |i|
109
+ mapping "#{l}#{i}".to_sym, "#{l}#{i}"
110
+ end
111
+ end
99
112
  end
100
113
  end
101
114
  end
@@ -42,36 +42,8 @@ module ActiveMerchant #:nodoc:
42
42
  # end
43
43
  # end
44
44
  class Notification < ActiveMerchant::Billing::Integrations::Notification
45
- # Overwrite this certificate. It contains the Paypal sandbox certificate by default.
46
- #
47
- # Example:
48
- # Paypal::Notification.paypal_cert = File::read("paypal_cert.pem")
49
- cattr_accessor :paypal_cert
50
- @@paypal_cert = """
51
- -----BEGIN CERTIFICATE-----
52
- MIIDoTCCAwqgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBmDELMAkGA1UEBhMCVVMx
53
- EzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcTCFNhbiBKb3NlMRUwEwYDVQQK
54
- EwxQYXlQYWwsIEluYy4xFjAUBgNVBAsUDXNhbmRib3hfY2VydHMxFDASBgNVBAMU
55
- C3NhbmRib3hfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0
56
- MDQxOTA3MDI1NFoXDTM1MDQxOTA3MDI1NFowgZgxCzAJBgNVBAYTAlVTMRMwEQYD
57
- VQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEVMBMGA1UEChMMUGF5
58
- UGFsLCBJbmMuMRYwFAYDVQQLFA1zYW5kYm94X2NlcnRzMRQwEgYDVQQDFAtzYW5k
59
- Ym94X2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG
60
- 9w0BAQEFAAOBjQAwgYkCgYEAt5bjv/0N0qN3TiBL+1+L/EjpO1jeqPaJC1fDi+cC
61
- 6t6tTbQ55Od4poT8xjSzNH5S48iHdZh0C7EqfE1MPCc2coJqCSpDqxmOrO+9QXsj
62
- HWAnx6sb6foHHpsPm7WgQyUmDsNwTWT3OGR398ERmBzzcoL5owf3zBSpRP0NlTWo
63
- nPMCAwEAAaOB+DCB9TAdBgNVHQ4EFgQUgy4i2asqiC1rp5Ms81Dx8nfVqdIwgcUG
64
- A1UdIwSBvTCBuoAUgy4i2asqiC1rp5Ms81Dx8nfVqdKhgZ6kgZswgZgxCzAJBgNV
65
- BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEV
66
- MBMGA1UEChMMUGF5UGFsLCBJbmMuMRYwFAYDVQQLFA1zYW5kYm94X2NlcnRzMRQw
67
- EgYDVQQDFAtzYW5kYm94X2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNv
68
- bYIBADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFc288DYGX+GX2+W
69
- P/dwdXwficf+rlG+0V9GBPJZYKZJQ069W/ZRkUuWFQ+Opd2yhPpneGezmw3aU222
70
- CGrdKhOrBJRRcpoO3FjHHmXWkqgbQqDWdG7S+/l8n1QfDPp+jpULOrcnGEUY41Im
71
- jZJTylbJQ1b5PBBjGiP0PpK48cdF
72
- -----END CERTIFICATE-----
73
- """
74
-
45
+ include PostsData
46
+
75
47
  # Was the transaction complete?
76
48
  def complete?
77
49
  status == "Completed"
@@ -144,6 +116,10 @@ jZJTylbJQ1b5PBBjGiP0PpK48cdF
144
116
  def test?
145
117
  params['test_ipn'] == '1'
146
118
  end
119
+
120
+ def account
121
+ params['business'] || params['receiver_email']
122
+ end
147
123
 
148
124
  # Acknowledge the transaction to paypal. This method has to be called after a new
149
125
  # ipn arrives. Paypal will verify that all the information we received are correct and will return a
@@ -159,26 +135,17 @@ jZJTylbJQ1b5PBBjGiP0PpK48cdF
159
135
  # else
160
136
  # ... log possible hacking attempt ...
161
137
  # end
162
- def acknowledge
138
+ def acknowledge
163
139
  payload = raw
164
140
 
165
- uri = URI.parse(Paypal.service_url)
166
- request_path = "#{uri.path}?cmd=_notify-validate"
167
-
168
- request = Net::HTTP::Post.new(request_path)
169
- request['Content-Length'] = "#{payload.size}"
170
- request['User-Agent'] = "Active Merchant -- http://home.leetsoft.com/am"
171
-
172
- http = Net::HTTP.new(uri.host, uri.port)
173
-
174
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @ssl_strict
175
- http.use_ssl = true
176
-
177
- request = http.request(request, payload)
178
-
179
- raise StandardError.new("Faulty paypal result: #{request.body}") unless ["VERIFIED", "INVALID"].include?(request.body)
141
+ response = ssl_post(Paypal.service_url + '?cmd=_notify-validate', payload,
142
+ 'Content-Length' => "#{payload.size}",
143
+ 'User-Agent' => "Active Merchant -- http://activemerchant.org"
144
+ )
145
+
146
+ raise StandardError.new("Faulty paypal result: #{response}") unless ["VERIFIED", "INVALID"].include?(response)
180
147
 
181
- request.body == "VERIFIED"
148
+ response == "VERIFIED"
182
149
  end
183
150
  end
184
151
  end
@@ -0,0 +1,4 @@
1
+ module ActiveMerchant #:nodoc:
2
+ class ActiveMerchantError < StandardError #:nodoc:
3
+ end
4
+ end
@@ -0,0 +1,22 @@
1
+ require 'cgi'
2
+
3
+ class PostData < Hash
4
+ class_inheritable_accessor :required_fields, :instance_writer => false
5
+ self.required_fields = []
6
+
7
+ def []=(key, value)
8
+ return if value.blank? && !required?(key)
9
+ super
10
+ end
11
+
12
+ def to_post_data
13
+ collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
14
+ end
15
+
16
+ alias_method :to_s, :to_post_data
17
+
18
+ private
19
+ def required?(key)
20
+ required_fields.include?(key)
21
+ end
22
+ end
@@ -1,9 +1,15 @@
1
1
  module ActiveMerchant #:nodoc:
2
+ class ConnectionError < ActiveMerchantError
3
+ end
4
+
2
5
  module PostsData #:nodoc:
3
6
 
4
7
  def self.included(base)
5
8
  base.class_inheritable_accessor :ssl_strict
6
9
  base.ssl_strict = true
10
+
11
+ base.class_inheritable_accessor :pem_password
12
+ base.pem_password = false
7
13
  end
8
14
 
9
15
  def ssl_post(url, data, headers = {})
@@ -12,19 +18,31 @@ module ActiveMerchant #:nodoc:
12
18
  http = Net::HTTP.new(uri.host, uri.port)
13
19
  http.use_ssl = true
14
20
 
15
- if self.class.ssl_strict
21
+ if ssl_strict
16
22
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
17
23
  http.ca_file = File.dirname(__FILE__) + '/../../certs/cacert.pem'
18
24
  else
19
25
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
20
26
  end
21
27
 
22
- unless @options[:pem].blank?
28
+ if @options && !@options[:pem].blank?
23
29
  http.cert = OpenSSL::X509::Certificate.new(@options[:pem])
24
- http.key = OpenSSL::PKey::RSA.new(@options[:pem])
30
+
31
+ if pem_password
32
+ raise ArgumentError, "The private key requires a password" if @options[:pem_password].blank?
33
+ http.key = OpenSSL::PKey::RSA.new(@options[:pem], @options[:pem_password])
34
+ else
35
+ http.key = OpenSSL::PKey::RSA.new(@options[:pem])
36
+ end
37
+ end
38
+
39
+ begin
40
+ http.post(uri.request_uri, data, headers).body
41
+ rescue EOFError => e
42
+ raise ConnectionError, "The remote server dropped the connection"
43
+ rescue Errno::ECONNREFUSED => e
44
+ raise ConnectionError, "The remote server refused the connection"
25
45
  end
26
-
27
- http.post(uri.path, data, headers).body
28
46
  end
29
47
  end
30
48
  end