activemerchant 1.106.0 → 1.108.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +79 -0
  3. data/README.md +2 -2
  4. data/lib/active_merchant/billing/gateways/adyen.rb +1 -1
  5. data/lib/active_merchant/billing/gateways/authorize_net.rb +1 -1
  6. data/lib/active_merchant/billing/gateways/blue_pay.rb +2 -2
  7. data/lib/active_merchant/billing/gateways/borgun.rb +15 -4
  8. data/lib/active_merchant/billing/gateways/braintree_blue.rb +11 -9
  9. data/lib/active_merchant/billing/gateways/checkout_v2.rb +20 -9
  10. data/lib/active_merchant/billing/gateways/clearhaus.rb +1 -1
  11. data/lib/active_merchant/billing/gateways/cyber_source.rb +74 -21
  12. data/lib/active_merchant/billing/gateways/d_local.rb +17 -5
  13. data/lib/active_merchant/billing/gateways/decidir.rb +29 -0
  14. data/lib/active_merchant/billing/gateways/ebanx.rb +13 -1
  15. data/lib/active_merchant/billing/gateways/elavon.rb +58 -5
  16. data/lib/active_merchant/billing/gateways/element.rb +13 -5
  17. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +2 -2
  18. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +2 -2
  19. data/lib/active_merchant/billing/gateways/forte.rb +7 -6
  20. data/lib/active_merchant/billing/gateways/global_collect.rb +30 -24
  21. data/lib/active_merchant/billing/gateways/hps.rb +4 -2
  22. data/lib/active_merchant/billing/gateways/iats_payments.rb +31 -14
  23. data/lib/active_merchant/billing/gateways/iridium.rb +4 -2
  24. data/lib/active_merchant/billing/gateways/iveri.rb +4 -1
  25. data/lib/active_merchant/billing/gateways/ixopay.rb +1 -0
  26. data/lib/active_merchant/billing/gateways/kushki.rb +34 -5
  27. data/lib/active_merchant/billing/gateways/litle.rb +6 -1
  28. data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -0
  29. data/lib/active_merchant/billing/gateways/netaxept.rb +1 -1
  30. data/lib/active_merchant/billing/gateways/netbanx.rb +1 -1
  31. data/lib/active_merchant/billing/gateways/opp.rb +13 -7
  32. data/lib/active_merchant/billing/gateways/optimal_payment.rb +4 -0
  33. data/lib/active_merchant/billing/gateways/orbital.rb +44 -2
  34. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  35. data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
  36. data/lib/active_merchant/billing/gateways/payu_latam.rb +1 -1
  37. data/lib/active_merchant/billing/gateways/pin.rb +1 -1
  38. data/lib/active_merchant/billing/gateways/quantum.rb +1 -1
  39. data/lib/active_merchant/billing/gateways/realex.rb +10 -3
  40. data/lib/active_merchant/billing/gateways/redsys.rb +1 -1
  41. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +1 -1
  42. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +1 -1
  43. data/lib/active_merchant/billing/gateways/stripe.rb +7 -2
  44. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +40 -6
  45. data/lib/active_merchant/billing/gateways/transact_pro.rb +2 -2
  46. data/lib/active_merchant/billing/gateways/trexle.rb +1 -1
  47. data/lib/active_merchant/billing/gateways/worldpay.rb +8 -6
  48. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  49. data/lib/active_merchant/connection.rb +40 -42
  50. data/lib/active_merchant/network_connection_retries.rb +10 -12
  51. data/lib/active_merchant/version.rb +1 -1
  52. metadata +5 -4
@@ -186,7 +186,7 @@ module ActiveMerchant #:nodoc:
186
186
  billing_address[:street2] = address[:address2]
187
187
  billing_address[:city] = address[:city]
188
188
  billing_address[:state] = address[:state]
189
- billing_address[:country] = address[:country]
189
+ billing_address[:country] = address[:country] unless address[:country].blank?
190
190
  billing_address[:postalCode] = address[:zip] if @options[:payment_country] == 'MX'
191
191
  billing_address[:phone] = address[:phone]
192
192
  billing_address
@@ -138,7 +138,7 @@ module ActiveMerchant #:nodoc:
138
138
  name: creditcard.name
139
139
  )
140
140
  elsif creditcard.kind_of?(String)
141
- if creditcard =~ /^card_/
141
+ if /^card_/.match?(creditcard)
142
142
  post[:card_token] = get_card_token(creditcard)
143
143
  else
144
144
  post[:customer_token] = creditcard
@@ -253,7 +253,7 @@ module ActiveMerchant #:nodoc:
253
253
  if node.has_elements?
254
254
  node.elements.each { |e| parse_element(reply, e) }
255
255
  else
256
- if node.parent.name =~ /item/
256
+ if /item/.match?(node.parent.name)
257
257
  parent = node.parent.name + (node.parent.attributes['id'] ? '_' + node.parent.attributes['id'] : '')
258
258
  reply[(parent + '_' + node.name).to_sym] = node.text
259
259
  else
@@ -230,13 +230,14 @@ module ActiveMerchant
230
230
  def add_address_and_customer_info(xml, options)
231
231
  billing_address = options[:billing_address] || options[:address]
232
232
  shipping_address = options[:shipping_address]
233
+ ipv4_address = ipv4?(options[:ip]) ? options[:ip] : nil
233
234
 
234
- return unless billing_address || shipping_address || options[:customer] || options[:invoice] || options[:ip]
235
+ return unless billing_address || shipping_address || options[:customer] || options[:invoice] || ipv4_address
235
236
 
236
237
  xml.tag! 'tssinfo' do
237
238
  xml.tag! 'custnum', options[:customer] if options[:customer]
238
239
  xml.tag! 'prodid', options[:invoice] if options[:invoice]
239
- xml.tag! 'custipaddress', options[:ip] if options[:ip]
240
+ xml.tag! 'custipaddress', options[:ip] if ipv4_address
240
241
 
241
242
  if billing_address
242
243
  xml.tag! 'address', 'type' => 'billing' do
@@ -309,7 +310,7 @@ module ActiveMerchant
309
310
 
310
311
  version = three_d_secure.fetch(:version, '')
311
312
  xml.tag! 'mpi' do
312
- if version =~ /^2/
313
+ if /^2/.match?(version)
313
314
  xml.tag! 'authentication_value', three_d_secure[:cavv]
314
315
  xml.tag! 'ds_trans_id', three_d_secure[:ds_transaction_id]
315
316
  else
@@ -369,6 +370,12 @@ module ActiveMerchant
369
370
  def sanitize_order_id(order_id)
370
371
  order_id.to_s.gsub(/[^a-zA-Z0-9\-_]/, '')
371
372
  end
373
+
374
+ def ipv4?(ip_address)
375
+ return false if ip_address.nil?
376
+
377
+ !ip_address.match(/\A\d+\.\d+\.\d+\.\d+\z/).nil?
378
+ end
372
379
  end
373
380
  end
374
381
  end
@@ -565,7 +565,7 @@ module ActiveMerchant #:nodoc:
565
565
 
566
566
  def clean_order_id(order_id)
567
567
  cleansed = order_id.gsub(/[^\da-zA-Z]/, '')
568
- if cleansed =~ /^\d{4}/
568
+ if /^\d{4}/.match?(cleansed)
569
569
  cleansed[0..11]
570
570
  else
571
571
  '%04d%s' % [rand(0..9999), cleansed[0...8]]
@@ -8,7 +8,7 @@ module ActiveMerchant #:nodoc:
8
8
 
9
9
  class_attribute :test_periodic_url, :live_periodic_url
10
10
 
11
- self.test_url = 'https://api.securepay.com.au/test/payment'
11
+ self.test_url = 'https://test.api.securepay.com.au/xmlapi/payment'
12
12
  self.live_url = 'https://api.securepay.com.au/xmlapi/payment'
13
13
 
14
14
  self.test_periodic_url = 'https://test.securepay.com.au/xmlapi/periodic'
@@ -149,7 +149,7 @@ module ActiveMerchant #:nodoc:
149
149
  def parse(response, action)
150
150
  result = {}
151
151
  document = REXML::Document.new(response)
152
- response_element = document.root.get_elements("//[@xsi:type='tns:#{action}Response']").first
152
+ response_element = document.root.get_elements("//*[@xsi:type='tns:#{action}Response']").first
153
153
  response_element.elements.each do |element|
154
154
  result[element.name.underscore] = element.text
155
155
  end
@@ -80,6 +80,11 @@ module ActiveMerchant #:nodoc:
80
80
  end
81
81
 
82
82
  def authorize(money, payment, options = {})
83
+ if ach?(payment)
84
+ direct_bank_error = 'Direct bank account transactions are not supported for authorize.'
85
+ return Response.new(false, direct_bank_error)
86
+ end
87
+
83
88
  MultiResponse.run do |r|
84
89
  if payment.is_a?(ApplePayPaymentToken)
85
90
  r.process { tokenize_apple_pay_token(payment) }
@@ -647,7 +652,7 @@ module ActiveMerchant #:nodoc:
647
652
  add_expand_parameters(parameters, options) if parameters
648
653
  response = api_request(method, url, parameters, options)
649
654
  response['webhook_id'] = options[:webhook_id] if options[:webhook_id]
650
- success = success_from(response)
655
+ success = success_from(response, options)
651
656
 
652
657
  card = card_from_response(response)
653
658
  avs_code = AVS_CODE_TRANSLATOR["line1: #{card["address_line1_check"]}, zip: #{card["address_zip_check"]}"]
@@ -681,7 +686,7 @@ module ActiveMerchant #:nodoc:
681
686
  success ? 'Transaction approved' : response.fetch('error', {'message' => 'No error details'})['message']
682
687
  end
683
688
 
684
- def success_from(response)
689
+ def success_from(response, options)
685
690
  !response.key?('error') && response['status'] != 'failed'
686
691
  end
687
692
 
@@ -20,7 +20,9 @@ module ActiveMerchant #:nodoc:
20
20
  add_capture_method(post, options)
21
21
  add_confirmation_method(post, options)
22
22
  add_customer(post, options)
23
- add_payment_method_token(post, payment_method, options)
23
+ payment_method = add_payment_method_token(post, payment_method, options)
24
+ return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
25
+
24
26
  add_metadata(post, options)
25
27
  add_return_url(post, options)
26
28
  add_connected_account(post, options)
@@ -41,7 +43,9 @@ module ActiveMerchant #:nodoc:
41
43
 
42
44
  def confirm_intent(intent_id, payment_method, options = {})
43
45
  post = {}
44
- add_payment_method_token(post, payment_method, options)
46
+ payment_method = add_payment_method_token(post, payment_method, options)
47
+ return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
48
+
45
49
  CONFIRM_INTENT_ATTRIBUTES.each do |attribute|
46
50
  add_whitelisted_attribute(post, options, attribute)
47
51
  end
@@ -65,7 +69,9 @@ module ActiveMerchant #:nodoc:
65
69
  post = {}
66
70
  add_amount(post, money, options)
67
71
 
68
- add_payment_method_token(post, payment_method, options)
72
+ payment_method = add_payment_method_token(post, payment_method, options)
73
+ return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
74
+
69
75
  add_payment_method_types(post, options)
70
76
  add_customer(post, options)
71
77
  add_metadata(post, options)
@@ -106,8 +112,22 @@ module ActiveMerchant #:nodoc:
106
112
  end
107
113
 
108
114
  def refund(money, intent_id, options = {})
109
- intent = commit(:get, "payment_intents/#{intent_id}", nil, options)
110
- charge_id = intent.params.dig('charges', 'data')[0].dig('id')
115
+ if intent_id.include?('pi_')
116
+ intent = api_request(:get, "payment_intents/#{intent_id}", nil, options)
117
+
118
+ return Response.new(false, intent['error']['message'], intent) if intent['error']
119
+
120
+ charge_id = intent.try(:[], 'charges').try(:[], 'data').try(:[], 0).try(:[], 'id')
121
+
122
+ if charge_id.nil?
123
+ error_message = "No associated charge for #{intent['id']}"
124
+ error_message << "; payment_intent has a status of #{intent['status']}" if intent.try(:[], 'status') && intent.try(:[], 'status') != 'succeeded'
125
+ return Response.new(false, error_message, intent)
126
+ end
127
+ else
128
+ charge_id = intent_id
129
+ end
130
+
111
131
  super(money, charge_id, options)
112
132
  end
113
133
 
@@ -121,7 +141,9 @@ module ActiveMerchant #:nodoc:
121
141
  # If customer option is provided, create a payment method and attach to customer id
122
142
  # Otherwise, create a customer, then attach
123
143
  if payment_method.is_a?(StripePaymentToken) || payment_method.is_a?(ActiveMerchant::Billing::CreditCard)
124
- add_payment_method_token(params, payment_method, options)
144
+ payment_method = add_payment_method_token(params, payment_method, options)
145
+ return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
146
+
125
147
  if options[:customer]
126
148
  customer_id = options[:customer]
127
149
  else
@@ -191,6 +213,8 @@ module ActiveMerchant #:nodoc:
191
213
 
192
214
  if payment_method.is_a?(ActiveMerchant::Billing::CreditCard)
193
215
  p = create_payment_method(payment_method, options)
216
+ return p unless p.success?
217
+
194
218
  payment_method = p.params['id']
195
219
  end
196
220
 
@@ -271,6 +295,16 @@ module ActiveMerchant #:nodoc:
271
295
 
272
296
  options.merge(idempotency_key: "#{options[:idempotency_key]}-#{suffix}")
273
297
  end
298
+
299
+ def success_from(response, options)
300
+ if response['status'] == 'requires_action' && !options[:execute_threed]
301
+ response['error'] = {}
302
+ response['error']['message'] = 'Received unexpected 3DS authentication response. Use the execute_threed option to initiate a proper 3DS flow.'
303
+ return false
304
+ end
305
+
306
+ super(response, options)
307
+ end
274
308
  end
275
309
  end
276
310
  end
@@ -162,7 +162,7 @@ module ActiveMerchant #:nodoc:
162
162
  end
163
163
 
164
164
  def parse(body)
165
- if body =~ /^ID:/
165
+ if /^ID:/.match?(body)
166
166
  body.split('~').reduce(Hash.new) { |h, v|
167
167
  m = v.match('(.*?):(.*)')
168
168
  h.merge!(m[1].underscore.to_sym => m[2])
@@ -197,7 +197,7 @@ module ActiveMerchant #:nodoc:
197
197
  end
198
198
 
199
199
  def split_authorization(authorization)
200
- if authorization =~ /|/
200
+ if /|/.match?(authorization)
201
201
  identifier, amount = authorization.split('|')
202
202
  [identifier, amount.to_i]
203
203
  else
@@ -137,7 +137,7 @@ module ActiveMerchant #:nodoc:
137
137
  name: creditcard.name
138
138
  )
139
139
  elsif creditcard.kind_of?(String)
140
- if creditcard =~ /^token_/
140
+ if /^token_/.match?(creditcard)
141
141
  post[:card_token] = creditcard
142
142
  else
143
143
  post[:customer_token] = creditcard
@@ -94,10 +94,12 @@ module ActiveMerchant #:nodoc:
94
94
  r.process { refund_request(money, authorization, options) }
95
95
  end
96
96
 
97
- return response if response.success?
98
- return response unless options[:force_full_refund_if_unsettled]
99
-
100
- void(authorization, options) if response.params['last_event'] == 'AUTHORISED'
97
+ if !response.success? && options[:force_full_refund_if_unsettled] &&
98
+ response.params['last_event'] == 'AUTHORISED'
99
+ void(authorization, options)
100
+ else
101
+ response
102
+ end
101
103
  end
102
104
 
103
105
  # Credits only function on a Merchant ID/login/profile flagged for Payouts
@@ -404,7 +406,7 @@ module ActiveMerchant #:nodoc:
404
406
  def add_three_d_secure(three_d_secure, xml)
405
407
  xml.info3DSecure do
406
408
  xml.threeDSVersion three_d_secure[:version]
407
- if three_d_secure[:version] =~ /^2/
409
+ if /^2/.match?(three_d_secure[:version])
408
410
  xml.dsTransactionId three_d_secure[:ds_transaction_id]
409
411
  else
410
412
  xml.xid three_d_secure[:xid]
@@ -580,7 +582,7 @@ module ActiveMerchant #:nodoc:
580
582
  xml = ssl_post(url, request, headers(options))
581
583
  raw = parse(action, xml)
582
584
  if options[:execute_threed]
583
- raw[:cookie] = @cookie
585
+ raw[:cookie] = @cookie if defined?(@cookie)
584
586
  raw[:session_id] = options[:session_id]
585
587
  raw[:is3DSOrder] = true
586
588
  end
@@ -17,7 +17,7 @@ module ActiveMerchant #:nodoc:
17
17
  attr_accessor :payment_cryptogram, :eci, :transaction_id
18
18
  attr_writer :source
19
19
 
20
- SOURCES = %i(apple_pay android_pay google_pay)
20
+ SOURCES = %i(apple_pay android_pay google_pay network_token)
21
21
 
22
22
  def source
23
23
  if defined?(@source) && SOURCES.include?(@source)
@@ -73,52 +73,50 @@ module ActiveMerchant
73
73
  headers['connection'] ||= 'close'
74
74
 
75
75
  retry_exceptions(max_retries: max_retries, logger: logger, tag: tag) do
76
- begin
77
- info "connection_http_method=#{method.to_s.upcase} connection_uri=#{endpoint}", tag
78
-
79
- result = nil
80
-
81
- realtime = Benchmark.realtime do
82
- http.start unless http.started?
83
- @ssl_connection = http.ssl_connection
84
- info "connection_ssl_version=#{ssl_connection[:version]} connection_ssl_cipher=#{ssl_connection[:cipher]}", tag
85
-
86
- result =
87
- case method
88
- when :get
89
- raise ArgumentError, 'GET requests do not support a request body' if body
90
-
91
- http.get(endpoint.request_uri, headers)
92
- when :post
76
+ info "connection_http_method=#{method.to_s.upcase} connection_uri=#{endpoint}", tag
77
+
78
+ result = nil
79
+
80
+ realtime = Benchmark.realtime do
81
+ http.start unless http.started?
82
+ @ssl_connection = http.ssl_connection
83
+ info "connection_ssl_version=#{ssl_connection[:version]} connection_ssl_cipher=#{ssl_connection[:cipher]}", tag
84
+
85
+ result =
86
+ case method
87
+ when :get
88
+ raise ArgumentError, 'GET requests do not support a request body' if body
89
+
90
+ http.get(endpoint.request_uri, headers)
91
+ when :post
92
+ debug body
93
+ http.post(endpoint.request_uri, body, RUBY_184_POST_HEADERS.merge(headers))
94
+ when :put
95
+ debug body
96
+ http.put(endpoint.request_uri, body, headers)
97
+ when :patch
98
+ debug body
99
+ http.patch(endpoint.request_uri, body, headers)
100
+ when :delete
101
+ # It's kind of ambiguous whether the RFC allows bodies
102
+ # for DELETE requests. But Net::HTTP's delete method
103
+ # very unambiguously does not.
104
+ if body
93
105
  debug body
94
- http.post(endpoint.request_uri, body, RUBY_184_POST_HEADERS.merge(headers))
95
- when :put
96
- debug body
97
- http.put(endpoint.request_uri, body, headers)
98
- when :patch
99
- debug body
100
- http.patch(endpoint.request_uri, body, headers)
101
- when :delete
102
- # It's kind of ambiguous whether the RFC allows bodies
103
- # for DELETE requests. But Net::HTTP's delete method
104
- # very unambiguously does not.
105
- if body
106
- debug body
107
- req = Net::HTTP::Delete.new(endpoint.request_uri, headers)
108
- req.body = body
109
- http.request(req)
110
- else
111
- http.delete(endpoint.request_uri, headers)
112
- end
106
+ req = Net::HTTP::Delete.new(endpoint.request_uri, headers)
107
+ req.body = body
108
+ http.request(req)
113
109
  else
114
- raise ArgumentError, "Unsupported request method #{method.to_s.upcase}"
110
+ http.delete(endpoint.request_uri, headers)
115
111
  end
116
- end
117
-
118
- info '--> %d %s (%d %.4fs)' % [result.code, result.message, result.body ? result.body.length : 0, realtime], tag
119
- debug result.body
120
- result
112
+ else
113
+ raise ArgumentError, "Unsupported request method #{method.to_s.upcase}"
114
+ end
121
115
  end
116
+
117
+ info '--> %d %s (%d %.4fs)' % [result.code, result.message, result.body ? result.body.length : 0, realtime], tag
118
+ debug result.body
119
+ result
122
120
  end
123
121
  ensure
124
122
  info 'connection_request_total_time=%.4fs' % [Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start], tag
@@ -21,18 +21,16 @@ module ActiveMerchant
21
21
  connection_errors = DEFAULT_CONNECTION_ERRORS.merge(options[:connection_exceptions] || {})
22
22
 
23
23
  retry_network_exceptions(options) do
24
- begin
25
- yield
26
- rescue Errno::ECONNREFUSED => e
27
- raise ActiveMerchant::RetriableConnectionError.new('The remote server refused the connection', e)
28
- rescue OpenSSL::X509::CertificateError => e
29
- NetworkConnectionRetries.log(options[:logger], :error, e.message, options[:tag])
30
- raise ActiveMerchant::ClientCertificateError, 'The remote server did not accept the provided SSL certificate'
31
- rescue Zlib::BufError
32
- raise ActiveMerchant::InvalidResponseError, 'The remote server replied with an invalid response'
33
- rescue *connection_errors.keys => e
34
- raise ActiveMerchant::ConnectionError.new(derived_error_message(connection_errors, e.class), e)
35
- end
24
+ yield
25
+ rescue Errno::ECONNREFUSED => e
26
+ raise ActiveMerchant::RetriableConnectionError.new('The remote server refused the connection', e)
27
+ rescue OpenSSL::X509::CertificateError => e
28
+ NetworkConnectionRetries.log(options[:logger], :error, e.message, options[:tag])
29
+ raise ActiveMerchant::ClientCertificateError, 'The remote server did not accept the provided SSL certificate'
30
+ rescue Zlib::BufError
31
+ raise ActiveMerchant::InvalidResponseError, 'The remote server replied with an invalid response'
32
+ rescue *connection_errors.keys => e
33
+ raise ActiveMerchant::ConnectionError.new(derived_error_message(connection_errors, e.class), e)
36
34
  end
37
35
  end
38
36
 
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = '1.106.0'
2
+ VERSION = '1.108.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemerchant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.106.0
4
+ version: 1.108.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-10 00:00:00.000000000 Z
11
+ date: 2020-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -412,7 +412,8 @@ files:
412
412
  homepage: http://activemerchant.org/
413
413
  licenses:
414
414
  - MIT
415
- metadata: {}
415
+ metadata:
416
+ allowed_push_host: https://rubygems.org
416
417
  post_install_message:
417
418
  rdoc_options: []
418
419
  require_paths:
@@ -421,7 +422,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
421
422
  requirements:
422
423
  - - ">="
423
424
  - !ruby/object:Gem::Version
424
- version: '2.3'
425
+ version: '2.5'
425
426
  required_rubygems_version: !ruby/object:Gem::Requirement
426
427
  requirements:
427
428
  - - ">="