activemerchant 1.129.0 → 1.133.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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +51 -1
  3. data/lib/active_merchant/billing/credit_card.rb +2 -0
  4. data/lib/active_merchant/billing/credit_card_methods.rb +7 -3
  5. data/lib/active_merchant/billing/gateways/adyen.rb +82 -2
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +3 -2
  7. data/lib/active_merchant/billing/gateways/borgun.rb +11 -8
  8. data/lib/active_merchant/billing/gateways/braintree_blue.rb +8 -7
  9. data/lib/active_merchant/billing/gateways/checkout_v2.rb +15 -8
  10. data/lib/active_merchant/billing/gateways/commerce_hub.rb +13 -4
  11. data/lib/active_merchant/billing/gateways/cyber_source.rb +32 -7
  12. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +6 -8
  13. data/lib/active_merchant/billing/gateways/d_local.rb +1 -0
  14. data/lib/active_merchant/billing/gateways/global_collect.rb +41 -19
  15. data/lib/active_merchant/billing/gateways/ipg.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
  17. data/lib/active_merchant/billing/gateways/mit.rb +18 -18
  18. data/lib/active_merchant/billing/gateways/nmi.rb +5 -0
  19. data/lib/active_merchant/billing/gateways/paypal_express.rb +2 -0
  20. data/lib/active_merchant/billing/gateways/payu_latam.rb +1 -1
  21. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +1 -1
  22. data/lib/active_merchant/billing/gateways/redsys.rb +2 -1
  23. data/lib/active_merchant/billing/gateways/safe_charge.rb +2 -1
  24. data/lib/active_merchant/billing/gateways/shift4.rb +5 -2
  25. data/lib/active_merchant/billing/gateways/stripe.rb +21 -5
  26. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +111 -68
  27. data/lib/active_merchant/billing/gateways/vpos.rb +1 -1
  28. data/lib/active_merchant/billing/gateways/worldpay.rb +12 -24
  29. data/lib/active_merchant/version.rb +1 -1
  30. metadata +3 -3
@@ -2,6 +2,8 @@ module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class GlobalCollectGateway < Gateway
4
4
  class_attribute :preproduction_url
5
+ class_attribute :ogone_direct_test
6
+ class_attribute :ogone_direct_live
5
7
 
6
8
  self.display_name = 'GlobalCollect'
7
9
  self.homepage_url = 'http://www.globalcollect.com/'
@@ -9,6 +11,8 @@ module ActiveMerchant #:nodoc:
9
11
  self.test_url = 'https://eu.sandbox.api-ingenico.com'
10
12
  self.preproduction_url = 'https://world.preprod.api-ingenico.com'
11
13
  self.live_url = 'https://world.api-ingenico.com'
14
+ self.ogone_direct_test = 'https://payment.preprod.direct.worldline-solutions.com'
15
+ self.ogone_direct_live = 'https://payment.direct.worldline-solutions.com'
12
16
 
13
17
  self.supported_countries = %w[AD AE AG AI AL AM AO AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BO BQ BR BS BT BW BY BZ CA CC CD CF CH CI CK CL CM CN CO CR CU CV CW CX CY CZ DE DJ DK DM DO DZ EC EE EG ER ES ET FI FJ FK FM FO FR GA GB GD GE GF GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HN HR HT HU ID IE IL IM IN IS IT JM JO JP KE KG KH KI KM KN KR KW KY KZ LA LB LC LI LK LR LS LT LU LV MA MC MD ME MF MG MH MK MM MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NG NI NL NO NP NR NU NZ OM PA PE PF PG PH PL PN PS PT PW QA RE RO RS RU RW SA SB SC SE SG SH SI SJ SK SL SM SN SR ST SV SZ TC TD TG TH TJ TL TM TN TO TR TT TV TW TZ UA UG US UY UZ VC VE VG VI VN WF WS ZA ZM ZW]
14
18
  self.default_currency = 'USD'
@@ -114,7 +118,7 @@ module ActiveMerchant #:nodoc:
114
118
  post['order']['references']['invoiceData'] = {
115
119
  'invoiceNumber' => options[:invoice]
116
120
  }
117
- add_airline_data(post, options)
121
+ add_airline_data(post, options) unless ogone_direct?
118
122
  add_lodging_data(post, options)
119
123
  add_number_of_installments(post, options) if options[:number_of_installments]
120
124
  end
@@ -248,9 +252,10 @@ module ActiveMerchant #:nodoc:
248
252
  end
249
253
 
250
254
  def add_amount(post, money, options = {})
255
+ currency_ogone = 'EUR' if ogone_direct?
251
256
  post['amountOfMoney'] = {
252
257
  'amount' => amount(money),
253
- 'currencyCode' => options[:currency] || currency(money)
258
+ 'currencyCode' => options[:currency] || currency_ogone || currency(money)
254
259
  }
255
260
  end
256
261
 
@@ -262,7 +267,7 @@ module ActiveMerchant #:nodoc:
262
267
  product_id = options[:payment_product_id] || BRAND_MAP[payment.brand]
263
268
  specifics_inputs = {
264
269
  'paymentProductId' => product_id,
265
- 'skipAuthentication' => 'true', # refers to 3DSecure
270
+ 'skipAuthentication' => options[:skip_authentication] || 'true', # refers to 3DSecure
266
271
  'skipFraudService' => 'true',
267
272
  'authorizationMode' => pre_authorization
268
273
  }
@@ -377,18 +382,24 @@ module ActiveMerchant #:nodoc:
377
382
  def add_external_cardholder_authentication_data(post, options)
378
383
  return unless threeds_2_options = options[:three_d_secure]
379
384
 
380
- authentication_data = {}
381
- authentication_data[:acsTransactionId] = threeds_2_options[:acs_transaction_id] if threeds_2_options[:acs_transaction_id]
382
- authentication_data[:cavv] = threeds_2_options[:cavv] if threeds_2_options[:cavv]
383
- authentication_data[:cavvAlgorithm] = threeds_2_options[:cavv_algorithm] if threeds_2_options[:cavv_algorithm]
384
- authentication_data[:directoryServerTransactionId] = threeds_2_options[:ds_transaction_id] if threeds_2_options[:ds_transaction_id]
385
- authentication_data[:eci] = threeds_2_options[:eci] if threeds_2_options[:eci]
386
- authentication_data[:threeDSecureVersion] = threeds_2_options[:version] if threeds_2_options[:version]
387
- authentication_data[:validationResult] = threeds_2_options[:authentication_response_status] if threeds_2_options[:authentication_response_status]
388
- authentication_data[:xid] = threeds_2_options[:xid] if threeds_2_options[:xid]
385
+ authentication_data = {
386
+ priorThreeDSecureData: { acsTransactionId: threeds_2_options[:acs_transaction_id] }.compact,
387
+ cavv: threeds_2_options[:cavv],
388
+ cavvAlgorithm: threeds_2_options[:cavv_algorithm],
389
+ directoryServerTransactionId: threeds_2_options[:ds_transaction_id],
390
+ eci: threeds_2_options[:eci],
391
+ threeDSecureVersion: threeds_2_options[:version] || options[:three_ds_version],
392
+ validationResult: threeds_2_options[:authentication_response_status],
393
+ xid: threeds_2_options[:xid],
394
+ acsTransactionId: threeds_2_options[:acs_transaction_id],
395
+ flow: threeds_2_options[:flow]
396
+ }.compact
389
397
 
390
398
  post['cardPaymentMethodSpecificInput'] ||= {}
391
399
  post['cardPaymentMethodSpecificInput']['threeDSecure'] ||= {}
400
+ post['cardPaymentMethodSpecificInput']['threeDSecure']['merchantFraudRate'] = threeds_2_options[:merchant_fraud_rate]
401
+ post['cardPaymentMethodSpecificInput']['threeDSecure']['exemptionRequest'] = threeds_2_options[:exemption_request]
402
+ post['cardPaymentMethodSpecificInput']['threeDSecure']['secureCorporatePayment'] = threeds_2_options[:secure_corporate_payment]
392
403
  post['cardPaymentMethodSpecificInput']['threeDSecure']['externalCardholderAuthenticationData'] = authentication_data unless authentication_data.empty?
393
404
  end
394
405
 
@@ -402,17 +413,28 @@ module ActiveMerchant #:nodoc:
402
413
 
403
414
  def url(action, authorization)
404
415
  return preproduction_url + uri(action, authorization) if @options[:url_override].to_s == 'preproduction'
416
+ return ogone_direct_url(action, authorization) if ogone_direct?
405
417
 
406
418
  (test? ? test_url : live_url) + uri(action, authorization)
407
419
  end
408
420
 
421
+ def ogone_direct_url(action, authorization)
422
+ (test? ? ogone_direct_test : ogone_direct_live) + uri(action, authorization)
423
+ end
424
+
425
+ def ogone_direct?
426
+ @options[:url_override].to_s == 'ogone_direct'
427
+ end
428
+
409
429
  def uri(action, authorization)
410
- uri = "/v1/#{@options[:merchant_id]}/"
430
+ version = ogone_direct? ? 'v2' : 'v1'
431
+ uri = "/#{version}/#{@options[:merchant_id]}/"
411
432
  case action
412
433
  when :authorize
413
434
  uri + 'payments'
414
435
  when :capture
415
- uri + "payments/#{authorization}/approve"
436
+ capture_name = ogone_direct? ? 'capture' : 'approve'
437
+ uri + "payments/#{authorization}/#{capture_name}"
416
438
  when :refund
417
439
  uri + "payments/#{authorization}/refund"
418
440
  when :void
@@ -423,7 +445,7 @@ module ActiveMerchant #:nodoc:
423
445
  end
424
446
 
425
447
  def idempotency_key_for_signature(options)
426
- "x-gcs-idempotence-key:#{options[:idempotency_key]}" if options[:idempotency_key]
448
+ "x-gcs-idempotence-key:#{options[:idempotency_key]}" if options[:idempotency_key] && !ogone_direct?
427
449
  end
428
450
 
429
451
  def commit(method, action, post, authorization: nil, options: {})
@@ -461,7 +483,7 @@ module ActiveMerchant #:nodoc:
461
483
  'Date' => date
462
484
  }
463
485
 
464
- headers['X-GCS-Idempotence-Key'] = options[:idempotency_key] if options[:idempotency_key]
486
+ headers['X-GCS-Idempotence-Key'] = options[:idempotency_key] if options[:idempotency_key] && !ogone_direct?
465
487
  headers
466
488
  end
467
489
 
@@ -474,13 +496,13 @@ module ActiveMerchant #:nodoc:
474
496
  #{uri(action, authorization)}
475
497
  REQUEST
476
498
  data = data.each_line.reject { |line| line.strip == '' }.join
477
- digest = OpenSSL::Digest.new('sha256')
499
+ digest = OpenSSL::Digest.new('SHA256')
478
500
  key = @options[:secret_api_key]
479
- "GCS v1HMAC:#{@options[:api_key_id]}:#{Base64.strict_encode64(OpenSSL::HMAC.digest(digest, key, data))}"
501
+ "GCS v1HMAC:#{@options[:api_key_id]}:#{Base64.strict_encode64(OpenSSL::HMAC.digest(digest, key, data)).strip}"
480
502
  end
481
503
 
482
504
  def date
483
- @date ||= Time.now.gmtime.strftime('%a, %d %b %Y %H:%M:%S %Z') # Must be same in digest and HTTP header
505
+ @date ||= Time.now.gmtime.strftime('%a, %d %b %Y %H:%M:%S GMT')
484
506
  end
485
507
 
486
508
  def content_type
@@ -2,7 +2,7 @@ module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class IpgGateway < Gateway
4
4
  self.test_url = 'https://test.ipg-online.com/ipgapi/services'
5
- self.live_url = 'https://www5.ipg-online.com'
5
+ self.live_url = 'https://www5.ipg-online.com/ipgapi/services'
6
6
 
7
7
  self.supported_countries = %w(AR)
8
8
  self.default_currency = 'ARS'
@@ -7,7 +7,7 @@ module ActiveMerchant #:nodoc:
7
7
  self.test_url = 'https://api-uat.kushkipagos.com/'
8
8
  self.live_url = 'https://api.kushkipagos.com/'
9
9
 
10
- self.supported_countries = %w[CL CO EC MX PE]
10
+ self.supported_countries = %w[BR CL CO EC MX PE]
11
11
  self.default_currency = 'USD'
12
12
  self.money_format = :dollars
13
13
  self.supported_cardtypes = %i[visa master american_express discover diners_club alia]
@@ -93,8 +93,7 @@ module ActiveMerchant #:nodoc:
93
93
  post_to_json_encrypt = encrypt(post_to_json, @options[:key_session])
94
94
 
95
95
  final_post = '<authorization>' + post_to_json_encrypt + '</authorization><dataID>' + @options[:user] + '</dataID>'
96
- json_post = {}
97
- json_post[:payload] = final_post
96
+ json_post = final_post
98
97
  commit('sale', json_post)
99
98
  end
100
99
 
@@ -114,8 +113,7 @@ module ActiveMerchant #:nodoc:
114
113
  post_to_json_encrypt = encrypt(post_to_json, @options[:key_session])
115
114
 
116
115
  final_post = '<capture>' + post_to_json_encrypt + '</capture><dataID>' + @options[:user] + '</dataID>'
117
- json_post = {}
118
- json_post[:payload] = final_post
116
+ json_post = final_post
119
117
  commit('capture', json_post)
120
118
  end
121
119
 
@@ -136,8 +134,7 @@ module ActiveMerchant #:nodoc:
136
134
  post_to_json_encrypt = encrypt(post_to_json, @options[:key_session])
137
135
 
138
136
  final_post = '<refund>' + post_to_json_encrypt + '</refund><dataID>' + @options[:user] + '</dataID>'
139
- json_post = {}
140
- json_post[:payload] = final_post
137
+ json_post = final_post
141
138
  commit('refund', json_post)
142
139
  end
143
140
 
@@ -145,10 +142,18 @@ module ActiveMerchant #:nodoc:
145
142
  true
146
143
  end
147
144
 
145
+ def extract_mit_responses_from_transcript(transcript)
146
+ groups = transcript.scan(/reading \d+ bytes(.*?)read \d+ bytes/m)
147
+ groups.map do |group|
148
+ group.first.scan(/-> "(.*?)"/).flatten.map(&:strip).join('')
149
+ end
150
+ end
151
+
148
152
  def scrub(transcript)
149
153
  ret_transcript = transcript
150
154
  auth_origin = ret_transcript[/<authorization>(.*?)<\/authorization>/, 1]
151
155
  unless auth_origin.nil?
156
+ auth_origin = auth_origin.gsub('\n', '')
152
157
  auth_decrypted = decrypt(auth_origin, @options[:key_session])
153
158
  auth_json = JSON.parse(auth_decrypted)
154
159
  auth_json['card'] = '[FILTERED]'
@@ -162,6 +167,7 @@ module ActiveMerchant #:nodoc:
162
167
 
163
168
  cap_origin = ret_transcript[/<capture>(.*?)<\/capture>/, 1]
164
169
  unless cap_origin.nil?
170
+ cap_origin = cap_origin.gsub('\n', '')
165
171
  cap_decrypted = decrypt(cap_origin, @options[:key_session])
166
172
  cap_json = JSON.parse(cap_decrypted)
167
173
  cap_json['apikey'] = '[FILTERED]'
@@ -173,6 +179,7 @@ module ActiveMerchant #:nodoc:
173
179
 
174
180
  ref_origin = ret_transcript[/<refund>(.*?)<\/refund>/, 1]
175
181
  unless ref_origin.nil?
182
+ ref_origin = ref_origin.gsub('\n', '')
176
183
  ref_decrypted = decrypt(ref_origin, @options[:key_session])
177
184
  ref_json = JSON.parse(ref_decrypted)
178
185
  ref_json['apikey'] = '[FILTERED]'
@@ -182,15 +189,10 @@ module ActiveMerchant #:nodoc:
182
189
  ret_transcript = ret_transcript.gsub(/<refund>(.*?)<\/refund>/, ref_tagged)
183
190
  end
184
191
 
185
- res_origin = ret_transcript[/#{Regexp.escape('reading ')}(.*?)#{Regexp.escape('read')}/m, 1]
186
- loop do
187
- break if res_origin.nil?
188
-
189
- resp_origin = res_origin[/#{Regexp.escape('"')}(.*?)#{Regexp.escape('"')}/m, 1]
190
- resp_decrypted = decrypt(resp_origin, @options[:key_session])
191
- ret_transcript[/#{Regexp.escape('reading ')}(.*?)#{Regexp.escape('read')}/m, 1] = resp_decrypted
192
- ret_transcript = ret_transcript.sub('reading ', 'response: ')
193
- res_origin = ret_transcript[/#{Regexp.escape('reading ')}(.*?)#{Regexp.escape('read')}/m, 1]
192
+ groups = extract_mit_responses_from_transcript(transcript)
193
+ groups.each do |group|
194
+ group_decrypted = decrypt(group, @options[:key_session])
195
+ ret_transcript = ret_transcript.gsub('Conn close', "\n" + group_decrypted + "\nConn close")
194
196
  end
195
197
 
196
198
  ret_transcript
@@ -219,9 +221,7 @@ module ActiveMerchant #:nodoc:
219
221
  end
220
222
 
221
223
  def commit(action, parameters)
222
- json_str = JSON.generate(parameters)
223
- cleaned_str = json_str.gsub('\n', '')
224
- raw_response = ssl_post(live_url, cleaned_str, { 'Content-type' => 'application/json' })
224
+ raw_response = ssl_post(live_url, parameters, { 'Content-type' => 'text/plain' })
225
225
  response = JSON.parse(decrypt(raw_response, @options[:key_session]))
226
226
 
227
227
  Response.new(
@@ -149,6 +149,7 @@ module ActiveMerchant #:nodoc:
149
149
 
150
150
  def add_invoice(post, money, options)
151
151
  post[:amount] = amount(money)
152
+ post[:surcharge] = options[:surcharge] if options[:surcharge]
152
153
  post[:orderid] = options[:order_id]
153
154
  post[:orderdescription] = options[:description]
154
155
  post[:currency] = options[:currency] || currency(money)
@@ -232,6 +233,9 @@ module ActiveMerchant #:nodoc:
232
233
  end
233
234
 
234
235
  if (shipping_address = options[:shipping_address])
236
+ first_name, last_name = split_names(shipping_address[:name])
237
+ post[:shipping_firstname] = first_name if first_name
238
+ post[:shipping_lastname] = last_name if last_name
235
239
  post[:shipping_company] = shipping_address[:company]
236
240
  post[:shipping_address1] = shipping_address[:address1]
237
241
  post[:shipping_address2] = shipping_address[:address2]
@@ -240,6 +244,7 @@ module ActiveMerchant #:nodoc:
240
244
  post[:shipping_country] = shipping_address[:country]
241
245
  post[:shipping_zip] = shipping_address[:zip]
242
246
  post[:shipping_phone] = shipping_address[:phone]
247
+ post[:shipping_email] = options[:shipping_email] if options[:shipping_email]
243
248
  end
244
249
 
245
250
  if (descriptor = options[:descriptors])
@@ -108,6 +108,7 @@ module ActiveMerchant #:nodoc:
108
108
  xml.tag! 'n2:PaymentAction', action
109
109
  xml.tag! 'n2:Token', options[:token]
110
110
  xml.tag! 'n2:PayerID', options[:payer_id]
111
+ xml.tag! 'n2:MsgSubID', options[:idempotency_key] if options[:idempotency_key]
111
112
  add_payment_details(xml, money, currency_code, options)
112
113
  end
113
114
  end
@@ -251,6 +252,7 @@ module ActiveMerchant #:nodoc:
251
252
  add_payment_details(xml, money, currency_code, options)
252
253
  xml.tag! 'n2:IPAddress', options[:ip]
253
254
  xml.tag! 'n2:MerchantSessionId', options[:merchant_session_id] if options[:merchant_session_id].present?
255
+ xml.tag! 'n2:MsgSubID', options[:idempotency_key] if options[:idempotency_key]
254
256
  end
255
257
  end
256
258
  end
@@ -455,7 +455,7 @@ module ActiveMerchant #:nodoc:
455
455
  when 'verify_credentials'
456
456
  response['error'] || 'FAILED'
457
457
  else
458
- response['transactionResponse']['errorCode'] || response['transactionResponse']['responseCode'] if response['transactionResponse']
458
+ response['transactionResponse']['paymentNetworkResponseCode'] || response['transactionResponse']['errorCode'] if response['transactionResponse']
459
459
  end
460
460
  end
461
461
 
@@ -2,7 +2,7 @@ module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class PaywayDotComGateway < Gateway
4
4
  self.test_url = 'https://paywaywsdev.com/PaywayWS/Payment/CreditCard'
5
- self.live_url = 'https://paywayws.com/PaywayWS/Payment/CreditCard'
5
+ self.live_url = 'https://paywayws.net/PaywayWS/Payment/CreditCard'
6
6
 
7
7
  self.supported_countries = %w[US CA]
8
8
  self.default_currency = 'USD'
@@ -39,7 +39,7 @@ module ActiveMerchant #:nodoc:
39
39
  self.live_url = 'https://sis.redsys.es/sis/operaciones'
40
40
  self.test_url = 'https://sis-t.redsys.es:25443/sis/operaciones'
41
41
 
42
- self.supported_countries = ['ES']
42
+ self.supported_countries = %w[ES FR GB IT PL PT]
43
43
  self.default_currency = 'EUR'
44
44
  self.money_format = :cents
45
45
 
@@ -538,6 +538,7 @@ module ActiveMerchant #:nodoc:
538
538
  xml.DS_MERCHANT_COF_INI data[:DS_MERCHANT_COF_INI]
539
539
  xml.DS_MERCHANT_COF_TYPE data[:DS_MERCHANT_COF_TYPE]
540
540
  xml.DS_MERCHANT_COF_TXNID data[:DS_MERCHANT_COF_TXNID] if data[:DS_MERCHANT_COF_TXNID]
541
+ xml.DS_MERCHANT_DIRECTPAYMENT 'false' if options[:stored_credential][:initial_transaction]
541
542
  end
542
543
  end
543
544
  end
@@ -73,10 +73,10 @@ module ActiveMerchant #:nodoc:
73
73
  add_transaction_data('Credit', post, money, options.merge!({ currency: original_currency }))
74
74
  post[:sg_CreditType] = 2
75
75
  post[:sg_AuthCode] = auth
76
- post[:sg_TransactionID] = transaction_id
77
76
  post[:sg_CCToken] = token
78
77
  post[:sg_ExpMonth] = exp_month
79
78
  post[:sg_ExpYear] = exp_year
79
+ post[:sg_TransactionID] = transaction_id unless options[:unreferenced_refund]
80
80
 
81
81
  commit(post)
82
82
  end
@@ -86,6 +86,7 @@ module ActiveMerchant #:nodoc:
86
86
 
87
87
  add_payment(post, payment, options)
88
88
  add_transaction_data('Credit', post, money, options)
89
+ add_customer_details(post, payment, options)
89
90
 
90
91
  post[:sg_CreditType] = 1
91
92
 
@@ -91,7 +91,7 @@ module ActiveMerchant #:nodoc:
91
91
  commit(action, post, options)
92
92
  end
93
93
 
94
- def refund(money, authorization, options = {})
94
+ def refund(money, payment_method, options = {})
95
95
  post = {}
96
96
  action = 'refund'
97
97
 
@@ -99,12 +99,15 @@ module ActiveMerchant #:nodoc:
99
99
  add_invoice(post, money, options)
100
100
  add_clerk(post, options)
101
101
  add_transaction(post, options)
102
- add_card(action, post, get_card_token(authorization), options)
102
+ card_token = payment_method.is_a?(CreditCard) ? get_card_token(payment_method) : payment_method
103
+ add_card(action, post, card_token, options)
103
104
  add_card_present(post, options)
104
105
 
105
106
  commit(action, post, options)
106
107
  end
107
108
 
109
+ alias credit refund
110
+
108
111
  def void(authorization, options = {})
109
112
  options[:invoice] = get_invoice(authorization)
110
113
  commit('invoice', {}, options)
@@ -652,18 +652,19 @@ module ActiveMerchant #:nodoc:
652
652
  end
653
653
  end
654
654
 
655
- def headers(options = {})
656
- key = options[:key] || @api_key
657
- idempotency_key = options[:idempotency_key]
655
+ def key(options = {})
656
+ options[:key] || @api_key
657
+ end
658
658
 
659
+ def headers(options = {})
659
660
  headers = {
660
- 'Authorization' => 'Basic ' + Base64.strict_encode64(key.to_s + ':').strip,
661
+ 'Authorization' => 'Basic ' + Base64.strict_encode64(key(options).to_s + ':').strip,
661
662
  'User-Agent' => "Stripe/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
662
663
  'Stripe-Version' => api_version(options),
663
664
  'X-Stripe-Client-User-Agent' => stripe_client_user_agent(options),
664
665
  'X-Stripe-Client-User-Metadata' => { ip: options[:ip] }.to_json
665
666
  }
666
- headers['Idempotency-Key'] = idempotency_key if idempotency_key
667
+ headers['Idempotency-Key'] = options[:idempotency_key] if options[:idempotency_key]
667
668
  headers['Stripe-Account'] = options[:stripe_account] if options[:stripe_account]
668
669
  headers
669
670
  end
@@ -694,6 +695,9 @@ module ActiveMerchant #:nodoc:
694
695
 
695
696
  def commit(method, url, parameters = nil, options = {})
696
697
  add_expand_parameters(parameters, options) if parameters
698
+
699
+ return Response.new(false, 'Invalid API Key provided') unless key_valid?(options)
700
+
697
701
  response = api_request(method, url, parameters, options)
698
702
  response['webhook_id'] = options[:webhook_id] if options[:webhook_id]
699
703
  success = success_from(response, options)
@@ -712,6 +716,18 @@ module ActiveMerchant #:nodoc:
712
716
  error_code: success ? nil : error_code_from(response))
713
717
  end
714
718
 
719
+ def key_valid?(options)
720
+ return true unless test?
721
+
722
+ %w(sk rk).each do |k|
723
+ if key(options).start_with?(k)
724
+ return false unless key(options).start_with?("#{k}_test")
725
+ end
726
+ end
727
+
728
+ true
729
+ end
730
+
715
731
  def authorization_from(success, url, method, response)
716
732
  return response.fetch('error', {})['charge'] unless success
717
733