braintree 4.40.0 → 4.41.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/lib/braintree/client_token_gateway.rb +10 -1
  3. data/lib/braintree/credit_card_gateway.rb +8 -2
  4. data/lib/braintree/credit_card_verification_gateway.rb +2 -0
  5. data/lib/braintree/customer_gateway.rb +11 -3
  6. data/lib/braintree/http.rb +4 -2
  7. data/lib/braintree/merchant_account_gateway.rb +2 -0
  8. data/lib/braintree/payment_method_gateway.rb +6 -1
  9. data/lib/braintree/payment_method_nonce_gateway.rb +4 -0
  10. data/lib/braintree/paypal_account_gateway.rb +6 -1
  11. data/lib/braintree/plan_gateway.rb +4 -0
  12. data/lib/braintree/sepa_direct_debit_account_gateway.rb +4 -0
  13. data/lib/braintree/subscription_gateway.rb +6 -0
  14. data/lib/braintree/testing_gateway.rb +4 -0
  15. data/lib/braintree/transaction.rb +6 -0
  16. data/lib/braintree/transaction_gateway.rb +16 -7
  17. data/lib/braintree/transaction_line_item_gateway.rb +3 -1
  18. data/lib/braintree/transaction_search.rb +1 -0
  19. data/lib/braintree/us_bank_account_gateway.rb +2 -0
  20. data/lib/braintree/us_bank_account_verification_gateway.rb +4 -0
  21. data/lib/braintree/version.rb +1 -1
  22. data/spec/integration/braintree/client_api/client_token_spec.rb +14 -0
  23. data/spec/integration/braintree/customer_spec.rb +43 -0
  24. data/spec/integration/braintree/transaction_search_spec.rb +95 -0
  25. data/spec/integration/braintree/transaction_spec.rb +81 -1
  26. data/spec/unit/braintree/client_token_spec.rb +72 -0
  27. data/spec/unit/braintree/credit_card_spec.rb +26 -0
  28. data/spec/unit/braintree/credit_card_verification_spec.rb +8 -0
  29. data/spec/unit/braintree/customer_spec.rb +26 -0
  30. data/spec/unit/braintree/http_spec.rb +44 -0
  31. data/spec/unit/braintree/merchant_account_spec.rb +11 -0
  32. data/spec/unit/braintree/package_tracking_spec.rb +2 -2
  33. data/spec/unit/braintree/payment_method_nonce_spec.rb +14 -0
  34. data/spec/unit/braintree/payment_method_spec.rb +20 -0
  35. data/spec/unit/braintree/paypal_account_spec.rb +20 -0
  36. data/spec/unit/braintree/plan_gateway_spec.rb +30 -0
  37. data/spec/unit/braintree/sepa_debit_account_spec.rb +14 -0
  38. data/spec/unit/braintree/subscription_spec.rb +20 -0
  39. data/spec/unit/braintree/test_transaction_spec.rb +18 -0
  40. data/spec/unit/braintree/transaction_gateway_spec.rb +10 -0
  41. data/spec/unit/braintree/transaction_line_item_spec.rb +11 -0
  42. data/spec/unit/braintree/transaction_search_spec.rb +25 -0
  43. data/spec/unit/braintree/transaction_spec.rb +68 -6
  44. data/spec/unit/braintree/us_bank_account_spec.rb +8 -0
  45. data/spec/unit/braintree/us_bank_account_verification_spec.rb +14 -0
  46. data/spec/unit/braintree/util_spec.rb +37 -0
  47. metadata +7 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a358a5cff7db74d5364a662ed1076dd786742d6d6f75b0f9c040fda06353a955
4
- data.tar.gz: b78e2a6f20ab1207515ea76f3e7aaa6a367283b10821b026c9f89498e2e8f35c
3
+ metadata.gz: 874cd322dda721874dc4418b2f6ca24116b9395f7affc02d43fe056f43424b3a
4
+ data.tar.gz: 8c73ed2ec27ecf6b916474bc12dc14bde985c48107a53bdcea17a65a216cc3d5
5
5
  SHA512:
6
- metadata.gz: 7fbb0b0ca10ec35cd3e8e6d34476eaada51e465caf4aa25a00e6d61fdbafea147a25579ed012717f2b2fec3da184d823dd0756add7738d8e4bcf1a8abea1dd2d
7
- data.tar.gz: 7374cd696e006db551149f9363194c3a8ecafc7ec607b93b6a53f2eeb3eb2961e4b63bd68d20c2ea0f5262fab405597e924219b7e76fd514b0a398c367fa7403
6
+ metadata.gz: f8f4fa7af94d5b317dc5efa9aea66d1fbcf84f689e9cb19435f6899b8af8c39fb25063a8d0ff40e4025f42014e4c18555e9d4b2e779132b0fc73afc3f6204baa
7
+ data.tar.gz: 815d5927abfa22e7acbdf7fa4353d9408b0b0add7f66a5e1cbf43b2b2aaa03a5ac4f925eb25b69bcf1060ff04c01e9cdc9c908e560a4e6e7df9db14339ed886a
@@ -9,12 +9,21 @@ module Braintree
9
9
  end
10
10
 
11
11
  def generate(options={})
12
+ options = options.dup
13
+
12
14
  _validate_options(options)
13
15
 
14
16
  options[:version] ||= ClientToken::DEFAULT_VERSION
15
17
 
16
18
  Util.verify_keys(ClientTokenGateway._generate_signature, options)
17
19
 
20
+ if options.has_key?(:preferred_payment_method_token)
21
+ options[:payment_method_id] = options.delete(:preferred_payment_method_token)
22
+ options.delete("preferred_payment_method_token")
23
+ elsif options.has_key?("preferred_payment_method_token")
24
+ options[:payment_method_id] = options.delete("preferred_payment_method_token")
25
+ end
26
+
18
27
  params = {:client_token => options}
19
28
  result = @config.http.post("#{@config.base_merchant_path}/client_token", params)
20
29
 
@@ -27,7 +36,7 @@ module Braintree
27
36
 
28
37
  def self._generate_signature
29
38
  [
30
- :address_id, :customer_id, :proxy_merchant_id, :merchant_account_id,
39
+ :address_id, :customer_id, :merchant_account_id, :preferred_payment_method_token, :proxy_merchant_id,
31
40
  :version,
32
41
  {:domains => [:_any_key_]},
33
42
  {:options => [:fail_on_duplicate_payment_method, :fail_on_duplicate_payment_method_for_customer, :make_default, :verify_card]}
@@ -39,6 +39,8 @@ module Braintree
39
39
  end
40
40
 
41
41
  def delete(token)
42
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
43
+
42
44
  @config.http.delete("#{@config.base_merchant_path}/payment_methods/credit_card/#{token}")
43
45
  end
44
46
 
@@ -55,7 +57,8 @@ module Braintree
55
57
  end
56
58
 
57
59
  def find(token)
58
- raise ArgumentError if token.nil? || token.to_s.strip == ""
60
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
61
+
59
62
  response = @config.http.get("#{@config.base_merchant_path}/payment_methods/credit_card/#{token}")
60
63
  CreditCard._new(@gateway, response[:credit_card])
61
64
  rescue NotFoundError
@@ -63,7 +66,8 @@ module Braintree
63
66
  end
64
67
 
65
68
  def from_nonce(nonce)
66
- raise ArgumentError if nonce.nil? || nonce.to_s.strip == ""
69
+ raise ArgumentError, "nonce contains invalid characters" if Util.invalid_path_segment?(nonce)
70
+
67
71
  response = @config.http.get("#{@config.base_merchant_path}/payment_methods/from_nonce/#{nonce}")
68
72
  CreditCard._new(@gateway, response[:credit_card])
69
73
  rescue NotFoundError
@@ -71,6 +75,8 @@ module Braintree
71
75
  end
72
76
 
73
77
  def update(token, attributes)
78
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
79
+
74
80
  # NEXT_MAJOR_VERSION remove this check
75
81
  if attributes.has_key?(:venmo_sdk_payment_method_code) || attributes.has_key?(:venmo_sdk_session)
76
82
  warn "[DEPRECATED] The Venmo SDK integration is Unsupported. Please update your integration to use Pay with Venmo instead."
@@ -8,6 +8,8 @@ module Braintree
8
8
 
9
9
  def find(id)
10
10
  raise ArgumentError if id.nil? || id.to_s.strip == ""
11
+ raise ArgumentError, "id contains invalid characters" if Util.invalid_path_segment?(id)
12
+
11
13
  response = @config.http.get("#{@config.base_merchant_path}/verifications/#{id}")
12
14
  CreditCardVerification._new(response[:verification])
13
15
  rescue NotFoundError
@@ -23,15 +23,19 @@ module Braintree
23
23
  end
24
24
 
25
25
  def delete(customer_id)
26
+ raise ArgumentError, "customer_id contains invalid characters" if Util.invalid_path_segment?(customer_id)
27
+
26
28
  @config.http.delete("#{@config.base_merchant_path}/customers/#{customer_id}")
27
29
  SuccessfulResult.new
28
30
  end
29
31
 
30
32
  def find(customer_id, options = {})
31
- raise ArgumentError, "customer_id contains invalid characters" unless customer_id.to_s =~ /\A[\w-]+\z/
32
- raise ArgumentError, "customer_id cannot be blank" if customer_id.nil?|| customer_id.to_s.strip == ""
33
+ raise ArgumentError, "customer_id contains invalid characters" if Util.invalid_path_segment?(customer_id)
34
+
35
+ association_filter_id = options[:association_filter_id]
36
+ raise ArgumentError, "association_filter_id contains invalid characters" if association_filter_id && Util.invalid_path_segment?(association_filter_id)
33
37
 
34
- query_params = options[:association_filter_id].nil? ? "" : "?association_filter_id=#{options[:association_filter_id]}"
38
+ query_params = association_filter_id.nil? ? "" : "?association_filter_id=#{association_filter_id}"
35
39
  response = @config.http.get("#{@config.base_merchant_path}/customers/#{customer_id}#{query_params}")
36
40
  Customer._new(@gateway, response[:customer])
37
41
  rescue NotFoundError
@@ -47,11 +51,15 @@ module Braintree
47
51
  end
48
52
 
49
53
  def transactions(customer_id, options = {})
54
+ raise ArgumentError, "customer_id contains invalid characters" if Util.invalid_path_segment?(customer_id)
55
+
50
56
  response = @config.http.post("#{@config.base_merchant_path}/customers/#{customer_id}/transaction_ids")
51
57
  ResourceCollection.new(response) { |ids| _fetch_transactions(customer_id, ids) }
52
58
  end
53
59
 
54
60
  def update(customer_id, attributes)
61
+ raise ArgumentError, "customer_id contains invalid characters" if Util.invalid_path_segment?(customer_id)
62
+
55
63
  Util.verify_keys(CustomerGateway._update_signature, attributes)
56
64
  _do_update(:put, "/customers/#{customer_id}", :customer => attributes)
57
65
  end
@@ -8,7 +8,8 @@ module Braintree
8
8
  end
9
9
 
10
10
  def delete(path, query_params = {})
11
- response = _http_do Net::HTTP::Delete, path
11
+ full_path = path + _build_query_string(query_params)
12
+ response = _http_do Net::HTTP::Delete, full_path
12
13
  if response.code.to_i == 200 || response.code.to_i == 204
13
14
  true
14
15
  elsif response.code.to_i == 422
@@ -19,7 +20,8 @@ module Braintree
19
20
  end
20
21
 
21
22
  def get(path, query_params = {})
22
- response = _http_do Net::HTTP::Get, path
23
+ full_path = path + _build_query_string(query_params)
24
+ response = _http_do Net::HTTP::Get, full_path
23
25
  if response.code.to_i == 200 || response.code.to_i == 422
24
26
  Xml.hash_from_xml(_body(response))
25
27
  else
@@ -22,6 +22,8 @@ module Braintree
22
22
 
23
23
  def find(merchant_account_id)
24
24
  raise ArgumentError if merchant_account_id.nil? || merchant_account_id.to_s.strip == ""
25
+ raise ArgumentError, "merchant_account_id contains invalid characters" if Util.invalid_path_segment?(merchant_account_id)
26
+
25
27
  response = @config.http.get("#{@config.base_merchant_path}/merchant_accounts/#{merchant_account_id}")
26
28
  MerchantAccount._new(@gateway, response[:merchant_account])
27
29
  rescue NotFoundError
@@ -33,6 +33,8 @@ module Braintree
33
33
  end
34
34
 
35
35
  def delete(token, options = {})
36
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
37
+
36
38
  Util.verify_keys(PaymentMethodGateway._delete_signature, options)
37
39
  query_param = "?" + Util.hash_to_query_string(options) if not options.empty?
38
40
  @config.http.delete("#{@config.base_merchant_path}/payment_methods/any/#{token}#{query_param}")
@@ -40,7 +42,8 @@ module Braintree
40
42
  end
41
43
 
42
44
  def find(token)
43
- raise ArgumentError if token.nil? || token.to_s.strip == ""
45
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
46
+
44
47
  response = @config.http.get("#{@config.base_merchant_path}/payment_methods/any/#{token}")
45
48
  if response.has_key?(:credit_card)
46
49
  CreditCard._new(@gateway, response[:credit_card])
@@ -64,6 +67,8 @@ module Braintree
64
67
  end
65
68
 
66
69
  def update(token, attributes)
70
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
71
+
67
72
  # NEXT_MAJOR_VERSION remove this check
68
73
  if attributes.has_key?(:venmo_sdk_payment_method_code) || attributes.has_key?(:venmo_sdk_session)
69
74
  warn "[DEPRECATED] The Venmo SDK integration is Unsupported. Please update your integration to use Pay with Venmo instead."
@@ -9,6 +9,8 @@ module Braintree
9
9
  end
10
10
 
11
11
  def create(payment_method_token, args = {payment_method_nonce: {}})
12
+ raise ArgumentError, "payment_method_token contains invalid characters" if Util.invalid_path_segment?(payment_method_token)
13
+
12
14
  Util.verify_keys(PaymentMethodNonceGateway._create_signature, args)
13
15
 
14
16
  response = @config.http.post("#{@config.base_merchant_path}/payment_methods/#{payment_method_token}/nonces", args)
@@ -30,6 +32,8 @@ module Braintree
30
32
  end
31
33
 
32
34
  def find(payment_method_nonce)
35
+ raise ArgumentError, "payment_method_nonce contains invalid characters" if Util.invalid_path_segment?(payment_method_nonce)
36
+
33
37
  response = @config.http.get("#{@config.base_merchant_path}/payment_method_nonces/#{payment_method_nonce}")
34
38
  payment_method_nonce = PaymentMethodNonce._new(@gateway, response.fetch(:payment_method_nonce))
35
39
  SuccessfulResult.new(:payment_method_nonce => payment_method_nonce)
@@ -7,7 +7,8 @@ module Braintree
7
7
  end
8
8
 
9
9
  def find(token)
10
- raise ArgumentError if token.nil? || token.to_s.strip == ""
10
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
11
+
11
12
  response = @config.http.get("#{@config.base_merchant_path}/payment_methods/paypal_account/#{token}")
12
13
  PayPalAccount._new(@gateway, response[:paypal_account])
13
14
  rescue NotFoundError
@@ -20,11 +21,15 @@ module Braintree
20
21
  end
21
22
 
22
23
  def update(token, attributes)
24
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
25
+
23
26
  Util.verify_keys(PayPalAccountGateway._update_signature, attributes)
24
27
  _do_update(:put, "/payment_methods/paypal_account/#{token}", :paypal_account => attributes)
25
28
  end
26
29
 
27
30
  def delete(token)
31
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
32
+
28
33
  @config.http.delete("#{@config.base_merchant_path}/payment_methods/paypal_account/#{token}")
29
34
  end
30
35
 
@@ -27,6 +27,8 @@ module Braintree
27
27
 
28
28
  def find(id)
29
29
  raise ArgumentError if id.nil? || id.to_s.strip == ""
30
+ raise ArgumentError, "id contains invalid characters" if Util.invalid_path_segment?(id)
31
+
30
32
  response = @config.http.get("#{@config.base_merchant_path}/plans/#{id}")
31
33
  Plan._new(@gateway, response[:plan])
32
34
  rescue NotFoundError
@@ -34,6 +36,8 @@ module Braintree
34
36
  end
35
37
 
36
38
  def update(plan_id, attributes)
39
+ raise ArgumentError, "plan_id contains invalid characters" if Util.invalid_path_segment?(plan_id)
40
+
37
41
  Util.verify_keys(PlanGateway._update_signature, attributes)
38
42
  response = @config.http.put("#{@config.base_merchant_path}/plans/#{plan_id}", :plan => attributes)
39
43
  if response[:plan]
@@ -8,6 +8,8 @@ module Braintree
8
8
 
9
9
  def find(token)
10
10
  raise ArgumentError if token.nil? || token.to_s.strip == ""
11
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
12
+
11
13
  response = @config.http.get("#{@config.base_merchant_path}/payment_methods/sepa_debit_account/#{token}")
12
14
  SepaDirectDebitAccount._new(@gateway, response[:sepa_debit_account])
13
15
  rescue NotFoundError
@@ -16,6 +18,8 @@ module Braintree
16
18
 
17
19
  def delete(token)
18
20
  raise ArgumentError if token.nil? || token.to_s.strip == ""
21
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
22
+
19
23
  @config.http.delete("#{@config.base_merchant_path}/payment_methods/sepa_debit_account/#{token}")
20
24
  SuccessfulResult.new
21
25
  rescue NotFoundError
@@ -9,6 +9,8 @@ module Braintree
9
9
  end
10
10
 
11
11
  def cancel(subscription_id)
12
+ raise ArgumentError, "subscription_id contains invalid characters" if Util.invalid_path_segment?(subscription_id)
13
+
12
14
  response = @config.http.put("#{@config.base_merchant_path}/subscriptions/#{subscription_id}/cancel")
13
15
  if response[:subscription]
14
16
  SuccessfulResult.new(:subscription => Subscription._new(@gateway, response[:subscription]))
@@ -36,6 +38,8 @@ module Braintree
36
38
 
37
39
  def find(id)
38
40
  raise ArgumentError if id.nil? || id.to_s.strip == ""
41
+ raise ArgumentError, "id contains invalid characters" if Util.invalid_path_segment?(id)
42
+
39
43
  response = @config.http.get("#{@config.base_merchant_path}/subscriptions/#{id}")
40
44
  Subscription._new(@gateway, response[:subscription])
41
45
  rescue NotFoundError
@@ -55,6 +59,8 @@ module Braintree
55
59
  end
56
60
 
57
61
  def update(subscription_id, attributes)
62
+ raise ArgumentError, "subscription_id contains invalid characters" if Util.invalid_path_segment?(subscription_id)
63
+
58
64
  Util.verify_keys(SubscriptionGateway._update_signature, attributes)
59
65
  response = @config.http.put("#{@config.base_merchant_path}/subscriptions/#{subscription_id}", :subscription => attributes)
60
66
  if response[:subscription]
@@ -10,6 +10,7 @@ module Braintree
10
10
 
11
11
  def settle(transaction_id)
12
12
  check_environment
13
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
13
14
 
14
15
  response = @config.http.put("#{@config.base_merchant_path}/transactions/#{transaction_id}/settle")
15
16
  @transaction_gateway._handle_transaction_response(response)
@@ -17,6 +18,7 @@ module Braintree
17
18
 
18
19
  def settlement_confirm(transaction_id)
19
20
  check_environment
21
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
20
22
 
21
23
  response = @config.http.put("#{@config.base_merchant_path}/transactions/#{transaction_id}/settlement_confirm")
22
24
  @transaction_gateway._handle_transaction_response(response)
@@ -24,6 +26,7 @@ module Braintree
24
26
 
25
27
  def settlement_decline(transaction_id)
26
28
  check_environment
29
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
27
30
 
28
31
  response = @config.http.put("#{@config.base_merchant_path}/transactions/#{transaction_id}/settlement_decline")
29
32
  @transaction_gateway._handle_transaction_response(response)
@@ -31,6 +34,7 @@ module Braintree
31
34
 
32
35
  def settlement_pending(transaction_id)
33
36
  check_environment
37
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
34
38
 
35
39
  response = @config.http.put("#{@config.base_merchant_path}/transactions/#{transaction_id}/settlement_pending")
36
40
  @transaction_gateway._handle_transaction_response(response)
@@ -3,6 +3,12 @@ module Braintree
3
3
  include BaseModule
4
4
  include Braintree::Util::IdEquality
5
5
 
6
+ module AchType
7
+ SameDay = "same_day"
8
+ Standard = "standard"
9
+ All = constants.map { |c| const_get(c) }
10
+ end
11
+
6
12
  module CreatedUsing
7
13
  FullInformation = "full_information"
8
14
  Token = "token"
@@ -22,7 +22,7 @@ module Braintree
22
22
  end
23
23
 
24
24
  def cancel_release(transaction_id)
25
- raise ArgumentError, "transaction_id is invalid" unless transaction_id =~ /\A[0-9a-z]+\z/
25
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
26
26
  response = @config.http.put("#{@config.base_merchant_path}/transactions/#{transaction_id}/cancel_release")
27
27
  _handle_transaction_response(response)
28
28
  end
@@ -42,6 +42,8 @@ module Braintree
42
42
  end
43
43
 
44
44
  def clone_transaction(transaction_id, attributes)
45
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
46
+
45
47
  Util.verify_keys(TransactionGateway._clone_signature, attributes)
46
48
  _do_create "/transactions/#{transaction_id}/clone", :transaction_clone => attributes
47
49
  end
@@ -59,7 +61,9 @@ module Braintree
59
61
  end
60
62
 
61
63
  def find(id)
62
- raise ArgumentError, "id can not be empty" if id.nil? || id.strip.to_s == ""
64
+ raise ArgumentError, "id can not be empty" if id.nil? || id.to_s.strip == ""
65
+ raise ArgumentError, "id contains invalid characters" if Util.invalid_path_segment?(id)
66
+
63
67
  response = @config.http.get("#{@config.base_merchant_path}/transactions/#{id}")
64
68
  Transaction._new(@gateway, response[:transaction])
65
69
  rescue NotFoundError
@@ -67,6 +71,8 @@ module Braintree
67
71
  end
68
72
 
69
73
  def refund(transaction_id, amount_or_options = nil)
74
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
75
+
70
76
  options = if amount_or_options.is_a?(Hash)
71
77
  amount_or_options
72
78
  else
@@ -103,7 +109,7 @@ module Braintree
103
109
  end
104
110
 
105
111
  def package_tracking(transaction_id, package_tracking_request)
106
- raise ArgumentError, "transaction_id is invalid" unless transaction_id =~ /\A[0-9a-z]+\z/
112
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
107
113
  Util.verify_keys(TransactionGateway._package_tracking_request_signature, package_tracking_request)
108
114
  _do_create "/transactions/#{transaction_id}/shipments", :shipment => package_tracking_request
109
115
  end
@@ -126,7 +132,7 @@ module Braintree
126
132
  end
127
133
 
128
134
  def submit_for_settlement(transaction_id, amount = nil, options = {})
129
- raise ArgumentError, "transaction_id is invalid" unless transaction_id =~ /\A[0-9a-z]+\z/
135
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
130
136
  Util.verify_keys(TransactionGateway._submit_for_settlement_signature, options)
131
137
  transaction_params = {:amount => amount}.merge(options)
132
138
  response = @config.http.put("#{@config.base_merchant_path}/transactions/#{transaction_id}/submit_for_settlement", :transaction => transaction_params)
@@ -138,7 +144,7 @@ module Braintree
138
144
  end
139
145
 
140
146
  def adjust_authorization(transaction_id, amount)
141
- raise ArgumentError, "transaction_id is invalid" unless transaction_id =~ /\A[0-9a-z]+\z/
147
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
142
148
  Util.verify_keys(TransactionGateway._adjust_authorization_signature, {})
143
149
  transaction_params = {:amount => amount}
144
150
  response = @config.http.put("#{@config.base_merchant_path}/transactions/#{transaction_id}/adjust_authorization", :transaction => transaction_params)
@@ -150,14 +156,14 @@ module Braintree
150
156
  end
151
157
 
152
158
  def update_details(transaction_id, options = {})
153
- raise ArgumentError, "transaction_id is invalid" unless transaction_id =~ /\A[0-9a-z]+\z/
159
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
154
160
  Util.verify_keys(TransactionGateway._update_details_signature, options)
155
161
  response = @config.http.put("#{@config.base_merchant_path}/transactions/#{transaction_id}/update_details", :transaction => options)
156
162
  _handle_transaction_response(response)
157
163
  end
158
164
 
159
165
  def submit_for_partial_settlement(authorized_transaction_id, amount = nil, options = {})
160
- raise ArgumentError, "authorized_transaction_id is invalid" unless authorized_transaction_id =~ /\A[0-9a-z]+\z/
166
+ raise ArgumentError, "authorized_transaction_id contains invalid characters" if Util.invalid_path_segment?(authorized_transaction_id)
161
167
  Util.verify_keys(TransactionGateway._submit_for_partial_settlement_signature, options)
162
168
  transaction_params = {:amount => amount}.merge(options)
163
169
  response = @config.http.post("#{@config.base_merchant_path}/transactions/#{authorized_transaction_id}/submit_for_partial_settlement", :transaction => transaction_params)
@@ -169,6 +175,8 @@ module Braintree
169
175
  end
170
176
 
171
177
  def void(transaction_id, options = {})
178
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
179
+
172
180
  transaction_params = options.empty? ? nil : options
173
181
  response = @config.http.put(
174
182
  "#{@config.base_merchant_path}/transactions/#{transaction_id}/void",
@@ -382,6 +390,7 @@ module Braintree
382
390
  :api_request_key,
383
391
  :merchant_account_id,
384
392
  :order_id,
393
+ :surcharge_amount,
385
394
  ]
386
395
  end
387
396
 
@@ -7,7 +7,9 @@ module Braintree
7
7
  end
8
8
 
9
9
  def find_all(transaction_id)
10
- raise ArgumentError, "transaction_id cannot be blank" if transaction_id.nil? || transaction_id.strip.to_s == ""
10
+ raise ArgumentError, "transaction_id cannot be blank" if transaction_id.nil? || transaction_id.to_s.strip == ""
11
+ raise ArgumentError, "transaction_id contains invalid characters" if Util.invalid_path_segment?(transaction_id)
12
+
11
13
  response = @config.http.get("#{@config.base_merchant_path}/transactions/#{transaction_id}/line_items")
12
14
  response[:line_items].map do |line_item_params|
13
15
  TransactionLineItem._new(@gateway, line_item_params)
@@ -46,6 +46,7 @@ module Braintree
46
46
  equality_fields :credit_card_expiration_date
47
47
  partial_match_fields :credit_card_number
48
48
 
49
+ multiple_value_field :ach_type, :allows => Transaction::AchType::All
49
50
  multiple_value_field :created_using, :allows => [
50
51
  Transaction::CreatedUsing::FullInformation,
51
52
  Transaction::CreatedUsing::Token
@@ -8,6 +8,8 @@ module Braintree
8
8
 
9
9
  def find(token)
10
10
  raise ArgumentError if token.nil? || token.to_s.strip == ""
11
+ raise ArgumentError, "token contains invalid characters" if Util.invalid_path_segment?(token)
12
+
11
13
  response = @config.http.get("#{@config.base_merchant_path}/payment_methods/us_bank_account/#{token}")
12
14
  UsBankAccount._new(@gateway, response[:us_bank_account])
13
15
  rescue NotFoundError
@@ -8,6 +8,8 @@ module Braintree
8
8
 
9
9
  def confirm_micro_transfer_amounts(id, deposit_amounts)
10
10
  raise ArgumentError if id.nil? || id.to_s.strip == "" || !deposit_amounts.kind_of?(Array)
11
+ raise ArgumentError, "id contains invalid characters" if Util.invalid_path_segment?(id)
12
+
11
13
  response = @config.http.put(
12
14
  "#{@config.base_merchant_path}/us_bank_account_verifications/#{id}/confirm_micro_transfer_amounts",
13
15
  :us_bank_account_verification => {
@@ -27,6 +29,8 @@ module Braintree
27
29
 
28
30
  def find(id)
29
31
  raise ArgumentError if id.nil? || id.to_s.strip == ""
32
+ raise ArgumentError, "id contains invalid characters" if Util.invalid_path_segment?(id)
33
+
30
34
  response = @config.http.get("#{@config.base_merchant_path}/us_bank_account_verifications/#{id}")
31
35
  UsBankAccountVerification._new(response[:us_bank_account_verification])
32
36
  rescue NotFoundError
@@ -1,7 +1,7 @@
1
1
  module Braintree
2
2
  module Version
3
3
  Major = 4
4
- Minor = 40
4
+ Minor = 41
5
5
  Tiny = 0
6
6
 
7
7
  String = "#{Major}.#{Minor}.#{Tiny}"
@@ -378,6 +378,20 @@ describe Braintree::ClientToken do
378
378
  end
379
379
  end
380
380
 
381
+ it "can pass preferred_payment_method_token" do
382
+ result = Braintree::Customer.create
383
+ raw_client_token = Braintree::ClientToken.generate(
384
+ :customer_id => result.customer.id,
385
+ :preferred_payment_method_token => "a-pmt",
386
+ )
387
+ client_token = decode_client_token(raw_client_token)
388
+
389
+ expect(client_token["paymentMethodIdJwt"]).not_to be_nil
390
+ jwt_segment = client_token["paymentMethodIdJwt"].split(".")[1]
391
+ jwt_payload = JSON.parse(Base64.urlsafe_decode64(jwt_segment + "=" * ((4 - jwt_segment.length % 4) % 4)))
392
+ expect(jwt_payload["pmid"]).to eq("a-pmt")
393
+ end
394
+
381
395
  it "can pass merchant_account_id" do
382
396
  merchant_account_id = SpecHelper::NonDefaultMerchantAccountId
383
397
 
@@ -2677,4 +2677,47 @@ describe Braintree::Customer do
2677
2677
  end
2678
2678
  end
2679
2679
 
2680
+ describe "path traversal" do
2681
+ it "self.update rejects a traversal customer_id and does not void the victim transaction" do
2682
+ transaction = Braintree::Transaction.sale!(
2683
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
2684
+ :credit_card => {
2685
+ :number => Braintree::Test::CreditCardNumbers::Visa,
2686
+ :expiration_date => "05/2009"
2687
+ },
2688
+ :options => {:submit_for_settlement => false},
2689
+ )
2690
+ traversal_id = "../transactions/#{transaction.id}/void"
2691
+
2692
+ expect do
2693
+ Braintree::Customer.update(traversal_id, :first_name => "HackerOne")
2694
+ end.to raise_error(ArgumentError, "customer_id contains invalid characters")
2695
+
2696
+ unaffected_transaction = Braintree::Transaction.find(transaction.id)
2697
+ expect(unaffected_transaction.status).to eq(Braintree::Transaction::Status::Authorized)
2698
+ end
2699
+
2700
+ it "self.delete rejects a traversal customer_id and does not delete the victim payment method" do
2701
+ create_result = Braintree::Customer.create(:first_name => "Victim")
2702
+ expect(create_result.success?).to eq(true)
2703
+ customer = create_result.customer
2704
+
2705
+ credit_card_result = Braintree::CreditCard.create(
2706
+ :customer_id => customer.id,
2707
+ :number => Braintree::Test::CreditCardNumbers::Visa,
2708
+ :expiration_date => "05/2009",
2709
+ )
2710
+ expect(credit_card_result.success?).to eq(true)
2711
+ token = credit_card_result.credit_card.token
2712
+ traversal_id = "../payment_methods/any/#{token}"
2713
+
2714
+ expect do
2715
+ Braintree::Customer.delete(traversal_id)
2716
+ end.to raise_error(ArgumentError, "customer_id contains invalid characters")
2717
+
2718
+ unaffected_credit_card = Braintree::CreditCard.find(token)
2719
+ expect(unaffected_credit_card.token).to eq(token)
2720
+ end
2721
+ end
2722
+
2680
2723
  end