activemerchant 1.129.0 → 1.133.0

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