activemerchant 1.106.0 → 1.108.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 (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
  - - ">="