activemerchant 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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