braintree 4.39.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/braintree/address_gateway.rb +13 -3
  3. data/lib/braintree/client_token_gateway.rb +10 -1
  4. data/lib/braintree/credit_card_gateway.rb +9 -2
  5. data/lib/braintree/credit_card_verification_gateway.rb +3 -0
  6. data/lib/braintree/customer_gateway.rb +11 -3
  7. data/lib/braintree/dispute_gateway.rb +7 -7
  8. data/lib/braintree/error_codes.rb +11 -0
  9. data/lib/braintree/http.rb +4 -2
  10. data/lib/braintree/merchant_account_gateway.rb +2 -0
  11. data/lib/braintree/payment_method_gateway.rb +7 -1
  12. data/lib/braintree/payment_method_nonce_gateway.rb +4 -0
  13. data/lib/braintree/paypal_account_gateway.rb +6 -1
  14. data/lib/braintree/plan_gateway.rb +4 -0
  15. data/lib/braintree/sepa_direct_debit_account_gateway.rb +4 -0
  16. data/lib/braintree/subscription_gateway.rb +6 -0
  17. data/lib/braintree/testing_gateway.rb +4 -0
  18. data/lib/braintree/three_d_secure_pass_thru.rb +11 -0
  19. data/lib/braintree/transaction.rb +6 -0
  20. data/lib/braintree/transaction_gateway.rb +17 -7
  21. data/lib/braintree/transaction_line_item_gateway.rb +3 -1
  22. data/lib/braintree/transaction_search.rb +1 -0
  23. data/lib/braintree/us_bank_account_gateway.rb +2 -0
  24. data/lib/braintree/us_bank_account_verification_gateway.rb +4 -0
  25. data/lib/braintree/util.rb +5 -0
  26. data/lib/braintree/version.rb +1 -1
  27. data/lib/braintree.rb +1 -0
  28. data/spec/integration/braintree/advanced_search_spec.rb +4 -7
  29. data/spec/integration/braintree/braintree_gateway_spec.rb +1 -2
  30. data/spec/integration/braintree/client_api/client_token_spec.rb +14 -0
  31. data/spec/integration/braintree/credit_card_spec.rb +94 -2
  32. data/spec/integration/braintree/credit_card_verification_spec.rb +33 -0
  33. data/spec/integration/braintree/customer_spec.rb +196 -5
  34. data/spec/integration/braintree/http_spec.rb +1 -1
  35. data/spec/integration/braintree/payment_method_spec.rb +77 -7
  36. data/spec/integration/braintree/samsung_pay_card_spec.rb +1 -1
  37. data/spec/integration/braintree/transaction_search_spec.rb +113 -13
  38. data/spec/integration/braintree/transaction_spec.rb +197 -17
  39. data/spec/unit/braintree/address_spec.rb +32 -0
  40. data/spec/unit/braintree/client_token_spec.rb +72 -0
  41. data/spec/unit/braintree/credit_card_spec.rb +28 -0
  42. data/spec/unit/braintree/credit_card_verification_spec.rb +8 -0
  43. data/spec/unit/braintree/customer_spec.rb +28 -0
  44. data/spec/unit/braintree/dispute_spec.rb +38 -0
  45. data/spec/unit/braintree/http_spec.rb +44 -0
  46. data/spec/unit/braintree/merchant_account_spec.rb +11 -0
  47. data/spec/unit/braintree/package_tracking_spec.rb +2 -2
  48. data/spec/unit/braintree/payment_method_nonce_spec.rb +14 -0
  49. data/spec/unit/braintree/payment_method_spec.rb +20 -0
  50. data/spec/unit/braintree/paypal_account_spec.rb +20 -0
  51. data/spec/unit/braintree/plan_gateway_spec.rb +30 -0
  52. data/spec/unit/braintree/sepa_debit_account_spec.rb +14 -0
  53. data/spec/unit/braintree/subscription_spec.rb +20 -0
  54. data/spec/unit/braintree/test_transaction_spec.rb +18 -0
  55. data/spec/unit/braintree/transaction_gateway_spec.rb +11 -0
  56. data/spec/unit/braintree/transaction_line_item_spec.rb +11 -0
  57. data/spec/unit/braintree/transaction_search_spec.rb +25 -0
  58. data/spec/unit/braintree/transaction_spec.rb +68 -6
  59. data/spec/unit/braintree/us_bank_account_spec.rb +8 -0
  60. data/spec/unit/braintree/us_bank_account_verification_spec.rb +14 -0
  61. data/spec/unit/braintree/util_spec.rb +37 -0
  62. metadata +8 -3
@@ -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,5 +1,10 @@
1
1
  module Braintree
2
2
  module Util
3
+ # Allowlist of the characters that make up a Braintree id/token.
4
+ def self.invalid_path_segment?(value)
5
+ !value.to_s.match?(/\A[A-Za-z0-9_-]+\z/)
6
+ end
7
+
3
8
  def self.extract_attribute_as_array(hash, attribute)
4
9
  raise UnexpectedError.new("Unprocessable entity due to an invalid request") if hash.nil?
5
10
  value = hash.has_key?(attribute) ? hash.delete(attribute) : []
@@ -1,7 +1,7 @@
1
1
  module Braintree
2
2
  module Version
3
3
  Major = 4
4
- Minor = 39
4
+ Minor = 41
5
5
  Tiny = 0
6
6
 
7
7
  String = "#{Major}.#{Minor}.#{Tiny}"
data/lib/braintree.rb CHANGED
@@ -138,6 +138,7 @@ require "braintree/risk_data/liability_shift"
138
138
  require "braintree/facilitated_details"
139
139
  require "braintree/facilitator_details"
140
140
  require "braintree/three_d_secure_info"
141
+ require "braintree/three_d_secure_pass_thru"
141
142
  require "braintree/settlement_batch_summary"
142
143
  require "braintree/settlement_batch_summary_gateway"
143
144
  require "braintree/resource_collection"
@@ -33,8 +33,7 @@ describe Braintree::AdvancedSearch do
33
33
  expect(collection).not_to include(subscription2)
34
34
  end
35
35
 
36
- # we are temporarily skipping this test until we have a more stable CI env
37
- xit "is_not" do
36
+ it "is_not" do
38
37
  id = rand(36**8).to_s(36)
39
38
  subscription1 = Braintree::Subscription.create(
40
39
  :payment_method_token => @credit_card.token,
@@ -81,8 +80,7 @@ describe Braintree::AdvancedSearch do
81
80
  expect(collection).not_to include(subscription2)
82
81
  end
83
82
 
84
- # we are temporarily skipping this test until we have a more stable CI env
85
- xit "ends_with" do
83
+ it "ends_with" do
86
84
  id = rand(36**8).to_s(36)
87
85
  subscription1 = Braintree::Subscription.create(
88
86
  :payment_method_token => @credit_card.token,
@@ -177,8 +175,7 @@ describe Braintree::AdvancedSearch do
177
175
  expect(collection).not_to include(subscription2)
178
176
  end
179
177
 
180
- # ignore until more stable CI
181
- xit "returns only matching results given an argument list" do
178
+ it "returns only matching results given an argument list" do
182
179
  subscription1 = Braintree::Subscription.create(
183
180
  :payment_method_token => @credit_card.token,
184
181
  :plan_id => SpecHelper::TriallessPlan[:id],
@@ -265,7 +262,7 @@ describe Braintree::AdvancedSearch do
265
262
 
266
263
  context "multiple_value_or_text_field" do
267
264
  describe "in" do
268
- xit "works for the in operator(temporarily disabling until more stable CI)" do
265
+ it "works for the in operator(temporarily disabling until more stable CI)" do
269
266
  Braintree::Subscription.create(
270
267
  :payment_method_token => @credit_card.token,
271
268
  :plan_id => SpecHelper::TriallessPlan[:id],
@@ -12,8 +12,7 @@ describe Braintree::Gateway do
12
12
  end
13
13
 
14
14
  describe "query" do
15
- # we are temporarily skipping this test until we have a more stable CI env
16
- xit "makes valid GraphQL queries when given a definition" do
15
+ it "makes valid GraphQL mutation queries for tokenizeCreditCard" do
17
16
  definition = <<-GRAPHQL
18
17
  mutation ExampleServerSideSingleUseToken($input: TokenizeCreditCardInput!) {
19
18
  tokenizeCreditCard(input: $input) {
@@ -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
 
@@ -312,6 +312,99 @@ describe Braintree::CreditCard do
312
312
  expect(result.success?).to eq(true)
313
313
  end
314
314
 
315
+ it "accepts a three_d_secure_pass_thru network specified in the request" do
316
+ customer = Braintree::Customer.create!
317
+ result = Braintree::CreditCard.create(
318
+ :customer_id => customer.id,
319
+ :payment_method_nonce => Braintree::Test::Nonce::TransactableVisa,
320
+ :three_d_secure_pass_thru => {
321
+ :eci_flag => "05",
322
+ :cavv => "some_cavv",
323
+ :xid => "some_xid",
324
+ :three_d_secure_version => "2.2.0",
325
+ :authentication_response => "Y",
326
+ :directory_response => "Y",
327
+ :cavv_algorithm => "2",
328
+ :ds_transaction_id => "some_ds_transaction_id",
329
+ :network => Braintree::ThreeDSecurePassThru::Network::Visa,
330
+ },
331
+ :options => {:verify_card => true},
332
+ )
333
+ expect(result.success?).to eq(true)
334
+ end
335
+
336
+ it "rejects invalid network value in 3ds pass thru params" do
337
+ customer = Braintree::Customer.create!
338
+ result = Braintree::CreditCard.create(
339
+ :customer_id => customer.id,
340
+ :payment_method_nonce => Braintree::Test::Nonce::Transactable,
341
+ :three_d_secure_pass_thru => {
342
+ :eci_flag => "05",
343
+ :cavv => "some_cavv",
344
+ :xid => "some_xid",
345
+ :three_d_secure_version => "2.2.0",
346
+ :authentication_response => "Y",
347
+ :directory_response => "Y",
348
+ :cavv_algorithm => "2",
349
+ :ds_transaction_id => "some_ds_transaction_id",
350
+ :network => "DISCOVER",
351
+ },
352
+ :options => {:verify_card => true},
353
+ )
354
+ expect(result).not_to be_success
355
+ error = result.errors.for(:verification).first
356
+ expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::NetworkIsInvalid)
357
+ expect(error.message).to eq("Network is invalid. Supported networks are eftpos, Visa, and Mastercard.")
358
+ end
359
+
360
+ it "rejects request where 3ds pass thru network does not match the payment instrument (VISA nonce, Mastercard network)" do
361
+ customer = Braintree::Customer.create!
362
+ result = Braintree::CreditCard.create(
363
+ :customer_id => customer.id,
364
+ :payment_method_nonce => Braintree::Test::Nonce::TransactableVisa,
365
+ :three_d_secure_pass_thru => {
366
+ :eci_flag => "05",
367
+ :cavv => "some_cavv",
368
+ :xid => "some_xid",
369
+ :three_d_secure_version => "2.2.0",
370
+ :authentication_response => "Y",
371
+ :directory_response => "Y",
372
+ :cavv_algorithm => "2",
373
+ :ds_transaction_id => "some_ds_transaction_id",
374
+ :network => Braintree::ThreeDSecurePassThru::Network::MasterCard,
375
+ },
376
+ :options => {:verify_card => true},
377
+ )
378
+ expect(result).not_to be_success
379
+ error = result.errors.for(:verification).first
380
+ expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::NetworkDoesNotMatchPaymentInstrument)
381
+ expect(error.message).to eq("Network does not match the payment instrument.")
382
+ end
383
+
384
+ it "rejects request where 3ds pass thru network does not support the merchant account currency" do
385
+ customer = Braintree::Customer.create!
386
+ result = Braintree::CreditCard.create(
387
+ :customer_id => customer.id,
388
+ :payment_method_nonce => Braintree::Test::Nonce::TransactableVisa,
389
+ :three_d_secure_pass_thru => {
390
+ :eci_flag => "05",
391
+ :cavv => "some_cavv",
392
+ :xid => "some_xid",
393
+ :three_d_secure_version => "2.2.0",
394
+ :authentication_response => "Y",
395
+ :directory_response => "Y",
396
+ :cavv_algorithm => "2",
397
+ :ds_transaction_id => "some_ds_transaction_id",
398
+ :network => Braintree::ThreeDSecurePassThru::Network::Eftpos,
399
+ },
400
+ :options => {:verify_card => true},
401
+ )
402
+ expect(result).not_to be_success
403
+ error = result.errors.for(:verification).first
404
+ expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::NetworkDoesNotSupportMerchantAccountCurrency)
405
+ expect(error.message).to eq("Network does not support the currency of the merchant account.")
406
+ end
407
+
315
408
  it "returns 3DS info on cc verification" do
316
409
  customer = Braintree::Customer.create!
317
410
  result = Braintree::CreditCard.create(
@@ -1263,8 +1356,7 @@ describe Braintree::CreditCard do
1263
1356
  end
1264
1357
 
1265
1358
  describe "self.expiring_between" do
1266
- #Disabling this test until we have a more stable CI
1267
- xit "finds payment methods expiring between the given dates" do
1359
+ it "finds payment methods expiring between the given dates" do
1268
1360
  next_year = Time.now.year + 1
1269
1361
  collection = Braintree::CreditCard.expiring_between(Time.mktime(next_year, 1), Time.mktime(next_year, 12))
1270
1362
  expect(collection.maximum_size).to be > 0
@@ -630,5 +630,38 @@ describe Braintree::CreditCardVerification, "search" do
630
630
  expect(result.credit_card_verification.processor_response_type).to eq(Braintree::ProcessorResponseTypes::Approved)
631
631
  expect(result.credit_card_verification.network_transaction_id).not_to be_nil
632
632
  end
633
+
634
+ it "can create a verification with a three_d_secure_pass_thru network specified" do
635
+ verification_params = {
636
+ :credit_card => {
637
+ :number => Braintree::Test::CreditCardNumbers::Visa,
638
+ :expiration_date => "12/12",
639
+ },
640
+ :options => {
641
+ :amount => "10.00",
642
+ },
643
+ :three_d_secure_pass_thru => {
644
+ :eci_flag => "05",
645
+ :cavv => "some_cavv",
646
+ :xid => "some_xid",
647
+ :three_d_secure_version => "2.2.0",
648
+ :authentication_response => "Y",
649
+ :directory_response => "Y",
650
+ :cavv_algorithm => "2",
651
+ :ds_transaction_id => "some_ds_id",
652
+ :network => Braintree::ThreeDSecurePassThru::Network::Visa,
653
+ },
654
+ }
655
+
656
+ result = Braintree::CreditCardVerification.create(verification_params)
657
+
658
+ expect(result).to be_success
659
+ expect(result.credit_card_verification.id).to match(/^\w{6,}$/)
660
+ expect(result.credit_card_verification.status).to eq(Braintree::CreditCardVerification::Status::Verified)
661
+ expect(result.credit_card_verification.processor_response_code).to eq("1000")
662
+ expect(result.credit_card_verification.processor_response_text).to eq("Approved")
663
+ expect(result.credit_card_verification.processor_response_type).to eq(Braintree::ProcessorResponseTypes::Approved)
664
+ expect(result.credit_card_verification.network_transaction_id).not_to be_nil
665
+ end
633
666
  end
634
667
  end
@@ -4,8 +4,7 @@ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
4
4
 
5
5
  describe Braintree::Customer do
6
6
  describe "self.all" do
7
- #Disabling test until we have a more stable CI
8
- xit "gets more than a page of customers" do
7
+ it "gets more than a page of customers" do
9
8
  customers = Braintree::Customer.all
10
9
  expect(customers.maximum_size).to be > 100
11
10
 
@@ -1242,7 +1241,7 @@ describe Braintree::Customer do
1242
1241
  expect(apple_pay_card.expiration_year).not_to be_nil
1243
1242
  expect(apple_pay_card.healthcare).not_to be_nil
1244
1243
  expect(apple_pay_card.issuing_bank).not_to be_nil
1245
- expect(apple_pay_card.payment_instrument_name).to eq("AmEx 41002")
1244
+ expect(apple_pay_card.payment_instrument_name).to match(/\AAmEx \d{4,5}\z/)
1246
1245
  expect(apple_pay_card.payroll).not_to be_nil
1247
1246
  expect(apple_pay_card.prepaid).not_to be_nil
1248
1247
  expect(apple_pay_card.prepaid_reloadable).not_to be_nil
@@ -1326,7 +1325,7 @@ describe Braintree::Customer do
1326
1325
  expect(venmo_account.username).not_to be_nil
1327
1326
  end
1328
1327
 
1329
- xit "returns associated us bank accounts" do
1328
+ it "returns associated us bank accounts" do
1330
1329
  result = Braintree::Customer.create(
1331
1330
  :payment_method_nonce => generate_non_plaid_us_bank_account_nonce,
1332
1331
  :credit_card => {
@@ -1693,7 +1692,8 @@ describe Braintree::Customer do
1693
1692
 
1694
1693
  apple_pay_card = result.customer.payment_methods.find { |pm| pm.is_a?(Braintree::ApplePayCard) }
1695
1694
  expect(apple_pay_card).not_to be_nil
1696
- expect(apple_pay_card.last_4).to eq(Braintree::Test::CreditCardNumbers::Visa[-4..-1])
1695
+ expect(apple_pay_card.card_type).to eq(Braintree::ApplePayCard::CardType::Visa)
1696
+ expect(apple_pay_card.last_4).to match(/\A\d{4}\z/)
1697
1697
  expect(apple_pay_card.cardholder_name).to eq("Updated Joe Cardholder")
1698
1698
 
1699
1699
  verification = apple_pay_card.verification
@@ -2084,6 +2084,154 @@ describe Braintree::Customer do
2084
2084
  expect(result).to be_success
2085
2085
  end
2086
2086
 
2087
+ it "accepts a three_d_secure_pass_thru network specified on customer create" do
2088
+ result = Braintree::Customer.create(
2089
+ :payment_method_nonce => Braintree::Test::Nonce::TransactableVisa,
2090
+ :credit_card => {
2091
+ :three_d_secure_pass_thru => {
2092
+ :eci_flag => "05",
2093
+ :cavv => "some_cavv",
2094
+ :xid => "some_xid",
2095
+ :three_d_secure_version => "2.2.0",
2096
+ :authentication_response => "Y",
2097
+ :directory_response => "Y",
2098
+ :cavv_algorithm => "2",
2099
+ :ds_transaction_id => "some_ds_transaction_id",
2100
+ :network => Braintree::ThreeDSecurePassThru::Network::Visa,
2101
+ },
2102
+ :options => {:verify_card => true},
2103
+ },
2104
+ )
2105
+ expect(result).to be_success
2106
+ end
2107
+
2108
+ it "rejects invalid network value in 3ds pass thru params on customer create" do
2109
+ result = Braintree::Customer.create(
2110
+ :payment_method_nonce => Braintree::Test::Nonce::Transactable,
2111
+ :credit_card => {
2112
+ :three_d_secure_pass_thru => {
2113
+ :eci_flag => "05",
2114
+ :cavv => "some_cavv",
2115
+ :xid => "some_xid",
2116
+ :three_d_secure_version => "2.2.0",
2117
+ :authentication_response => "Y",
2118
+ :directory_response => "Y",
2119
+ :cavv_algorithm => "2",
2120
+ :ds_transaction_id => "some_ds_transaction_id",
2121
+ :network => "DISCOVER",
2122
+ },
2123
+ :options => {:verify_card => true},
2124
+ },
2125
+ )
2126
+ expect(result).not_to be_success
2127
+ error = result.errors.for(:verification).first
2128
+ expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::NetworkIsInvalid)
2129
+ expect(error.message).to eq("Network is invalid. Supported networks are eftpos, Visa, and Mastercard.")
2130
+ end
2131
+
2132
+ it "rejects request where 3ds pass thru network does not match the payment instrument on customer create (VISA nonce, Mastercard network)" do
2133
+ result = Braintree::Customer.create(
2134
+ :payment_method_nonce => Braintree::Test::Nonce::TransactableVisa,
2135
+ :credit_card => {
2136
+ :three_d_secure_pass_thru => {
2137
+ :eci_flag => "05",
2138
+ :cavv => "some_cavv",
2139
+ :xid => "some_xid",
2140
+ :three_d_secure_version => "2.2.0",
2141
+ :authentication_response => "Y",
2142
+ :directory_response => "Y",
2143
+ :cavv_algorithm => "2",
2144
+ :ds_transaction_id => "some_ds_transaction_id",
2145
+ :network => Braintree::ThreeDSecurePassThru::Network::MasterCard,
2146
+ },
2147
+ :options => {:verify_card => true},
2148
+ },
2149
+ )
2150
+ expect(result).not_to be_success
2151
+ error = result.errors.for(:verification).first
2152
+ expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::NetworkDoesNotMatchPaymentInstrument)
2153
+ expect(error.message).to eq("Network does not match the payment instrument.")
2154
+ end
2155
+
2156
+ it "accepts a three_d_secure_pass_thru network specified on customer update" do
2157
+ customer = Braintree::Customer.create!
2158
+ result = Braintree::Customer.update(
2159
+ customer.id,
2160
+ :credit_card => {
2161
+ :number => Braintree::Test::CreditCardNumbers::Visa,
2162
+ :expiration_date => "05/2009",
2163
+ :three_d_secure_pass_thru => {
2164
+ :eci_flag => "05",
2165
+ :cavv => "some_cavv",
2166
+ :xid => "some_xid",
2167
+ :three_d_secure_version => "2.2.0",
2168
+ :authentication_response => "Y",
2169
+ :directory_response => "Y",
2170
+ :cavv_algorithm => "2",
2171
+ :ds_transaction_id => "some_ds_transaction_id",
2172
+ :network => Braintree::ThreeDSecurePassThru::Network::Visa,
2173
+ },
2174
+ :options => {:verify_card => true}
2175
+ },
2176
+ )
2177
+
2178
+ expect(result).to be_success
2179
+ end
2180
+
2181
+ it "rejects invalid network value in 3ds pass thru params on customer update" do
2182
+ customer = Braintree::Customer.create!
2183
+ result = Braintree::Customer.update(
2184
+ customer.id,
2185
+ :credit_card => {
2186
+ :number => Braintree::Test::CreditCardNumbers::Visa,
2187
+ :expiration_date => "05/2009",
2188
+ :three_d_secure_pass_thru => {
2189
+ :eci_flag => "05",
2190
+ :cavv => "some_cavv",
2191
+ :xid => "some_xid",
2192
+ :three_d_secure_version => "2.2.0",
2193
+ :authentication_response => "Y",
2194
+ :directory_response => "Y",
2195
+ :cavv_algorithm => "2",
2196
+ :ds_transaction_id => "some_ds_transaction_id",
2197
+ :network => "DISCOVER",
2198
+ },
2199
+ :options => {:verify_card => true}
2200
+ },
2201
+ )
2202
+ expect(result).not_to be_success
2203
+ error = result.errors.for(:verification).first
2204
+ expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::NetworkIsInvalid)
2205
+ expect(error.message).to eq("Network is invalid. Supported networks are eftpos, Visa, and Mastercard.")
2206
+ end
2207
+
2208
+ it "rejects request where 3ds pass thru network does not match the payment instrument on customer update (VISA card, Mastercard network)" do
2209
+ customer = Braintree::Customer.create!
2210
+ result = Braintree::Customer.update(
2211
+ customer.id,
2212
+ :credit_card => {
2213
+ :number => Braintree::Test::CreditCardNumbers::Visa,
2214
+ :expiration_date => "05/2009",
2215
+ :three_d_secure_pass_thru => {
2216
+ :eci_flag => "05",
2217
+ :cavv => "some_cavv",
2218
+ :xid => "some_xid",
2219
+ :three_d_secure_version => "2.2.0",
2220
+ :authentication_response => "Y",
2221
+ :directory_response => "Y",
2222
+ :cavv_algorithm => "2",
2223
+ :ds_transaction_id => "some_ds_transaction_id",
2224
+ :network => Braintree::ThreeDSecurePassThru::Network::MasterCard,
2225
+ },
2226
+ :options => {:verify_card => true}
2227
+ },
2228
+ )
2229
+ expect(result).not_to be_success
2230
+ error = result.errors.for(:verification).first
2231
+ expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::NetworkDoesNotMatchPaymentInstrument)
2232
+ expect(error.message).to eq("Network does not match the payment instrument.")
2233
+ end
2234
+
2087
2235
  it "returns 3DS info on cc verification" do
2088
2236
  result = Braintree::Customer.create(
2089
2237
  :payment_method_nonce => Braintree::Test::Nonce::ThreeDSecureVisaFullAuthentication,
@@ -2529,4 +2677,47 @@ describe Braintree::Customer do
2529
2677
  end
2530
2678
  end
2531
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
+
2532
2723
  end
@@ -97,7 +97,7 @@ describe Braintree::Http do
97
97
  end
98
98
 
99
99
  describe "ssl_version" do
100
- xit "causes failed requests to sandbox with incompatible SSL version" do
100
+ it "causes failed requests to sandbox with incompatible SSL version" do
101
101
  begin
102
102
  original_env = Braintree::Configuration.environment
103
103
  Braintree::Configuration.environment = :sandbox
@@ -92,8 +92,8 @@ describe Braintree::PaymentMethod do
92
92
  expect(apple_pay_card.bin).not_to be_nil
93
93
  expect(apple_pay_card.token).to eq(token)
94
94
  expect(apple_pay_card.card_type).to eq(Braintree::ApplePayCard::CardType::AmEx)
95
- expect(apple_pay_card.payment_instrument_name).to eq("AmEx 41002")
96
- expect(apple_pay_card.source_description).to eq("AmEx 41002")
95
+ expect(apple_pay_card.payment_instrument_name).to match(/\AAmEx \d{4,5}\z/)
96
+ expect(apple_pay_card.source_description).to match(/\AAmEx \d{4,5}\z/)
97
97
  expect(apple_pay_card.default).to eq(true)
98
98
  expect(apple_pay_card.image_url).to match(/apple_pay/)
99
99
  expect(apple_pay_card.expiration_month.to_i).to be > 0
@@ -127,8 +127,8 @@ describe Braintree::PaymentMethod do
127
127
  expect(apple_pay_card.bin).not_to be_nil
128
128
  expect(apple_pay_card.token).to eq(token)
129
129
  expect(apple_pay_card.card_type).to eq(Braintree::ApplePayCard::CardType::Visa)
130
- expect(apple_pay_card.payment_instrument_name).to eq("Visa 2006")
131
- expect(apple_pay_card.source_description).to eq("Visa 2006")
130
+ expect(apple_pay_card.payment_instrument_name).to match(/\AVisa \d{4}\z/)
131
+ expect(apple_pay_card.source_description).to match(/\AVisa \d{4}\z/)
132
132
  expect(apple_pay_card.default).to eq(true)
133
133
  expect(apple_pay_card.image_url).to match(/apple_pay/)
134
134
  expect(apple_pay_card.expiration_month.to_i).to be > 0
@@ -382,6 +382,76 @@ describe Braintree::PaymentMethod do
382
382
  expect(result).to be_success
383
383
  end
384
384
 
385
+ it "accepts a three_d_secure_pass_thru network specified in the request" do
386
+ customer = Braintree::Customer.create!
387
+ result = Braintree::PaymentMethod.create(
388
+ :customer_id => customer.id,
389
+ :payment_method_nonce => Braintree::Test::Nonce::TransactableVisa,
390
+ :three_d_secure_pass_thru => {
391
+ :eci_flag => "05",
392
+ :cavv => "some_cavv",
393
+ :xid => "some_xid",
394
+ :three_d_secure_version => "2.2.0",
395
+ :authentication_response => "Y",
396
+ :directory_response => "Y",
397
+ :cavv_algorithm => "2",
398
+ :ds_transaction_id => "some_ds_transaction_id",
399
+ :network => Braintree::ThreeDSecurePassThru::Network::Visa,
400
+ },
401
+ :options => {:verify_card => true},
402
+ )
403
+
404
+ expect(result).to be_success
405
+ end
406
+
407
+ it "rejects invalid network value in 3ds pass thru params" do
408
+ customer = Braintree::Customer.create!
409
+ result = Braintree::PaymentMethod.create(
410
+ :customer_id => customer.id,
411
+ :payment_method_nonce => Braintree::Test::Nonce::Transactable,
412
+ :three_d_secure_pass_thru => {
413
+ :eci_flag => "05",
414
+ :cavv => "some_cavv",
415
+ :xid => "some_xid",
416
+ :three_d_secure_version => "2.2.0",
417
+ :authentication_response => "Y",
418
+ :directory_response => "Y",
419
+ :cavv_algorithm => "2",
420
+ :ds_transaction_id => "some_ds_transaction_id",
421
+ :network => "DISCOVER",
422
+ },
423
+ :options => {:verify_card => true},
424
+ )
425
+ expect(result).not_to be_success
426
+ error = result.errors.for(:verification).first
427
+ expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::NetworkIsInvalid)
428
+ expect(error.message).to eq("Network is invalid. Supported networks are eftpos, Visa, and Mastercard.")
429
+ end
430
+
431
+ it "rejects request where 3ds pass thru network does not match the payment instrument (VISA nonce, Mastercard network)" do
432
+ customer = Braintree::Customer.create!
433
+ result = Braintree::PaymentMethod.create(
434
+ :customer_id => customer.id,
435
+ :payment_method_nonce => Braintree::Test::Nonce::TransactableVisa,
436
+ :three_d_secure_pass_thru => {
437
+ :eci_flag => "05",
438
+ :cavv => "some_cavv",
439
+ :xid => "some_xid",
440
+ :three_d_secure_version => "2.2.0",
441
+ :authentication_response => "Y",
442
+ :directory_response => "Y",
443
+ :cavv_algorithm => "2",
444
+ :ds_transaction_id => "some_ds_transaction_id",
445
+ :network => Braintree::ThreeDSecurePassThru::Network::MasterCard,
446
+ },
447
+ :options => {:verify_card => true},
448
+ )
449
+ expect(result).not_to be_success
450
+ error = result.errors.for(:verification).first
451
+ expect(error.code).to eq(Braintree::ErrorCodes::Verification::ThreeDSecurePassThru::NetworkDoesNotMatchPaymentInstrument)
452
+ expect(error.message).to eq("Network does not match the payment instrument.")
453
+ end
454
+
385
455
  it "returns 3DS info on cc verification" do
386
456
  customer = Braintree::Customer.create.customer
387
457
  result = Braintree::PaymentMethod.create(
@@ -813,7 +883,7 @@ describe Braintree::PaymentMethod do
813
883
  expect(update_result.payment_method.verification.credit_card[:account_type]).to eq("credit")
814
884
  end
815
885
 
816
- xit "updates the credit card with account_type debit" do
886
+ it "updates the credit card with account_type debit" do
817
887
  customer = Braintree::Customer.create!
818
888
  credit_card = Braintree::CreditCard.create!(
819
889
  :cardholder_name => "Original Holder",
@@ -1404,7 +1474,7 @@ describe Braintree::PaymentMethod do
1404
1474
  expect(apple_pay_card.image_url).to match(/apple_pay/)
1405
1475
  expect(apple_pay_card.expiration_month.to_i).to be > 0
1406
1476
  expect(apple_pay_card.expiration_year.to_i).to be > 0
1407
- expect(apple_pay_card.source_description).to eq("AmEx 41002")
1477
+ expect(apple_pay_card.source_description).to match(/\AAmEx \d{4,5}\z/)
1408
1478
  expect(apple_pay_card.customer_id).to eq(customer.id)
1409
1479
  end
1410
1480
 
@@ -1427,7 +1497,7 @@ describe Braintree::PaymentMethod do
1427
1497
  expect(apple_pay_card.image_url).to match(/apple_pay/)
1428
1498
  expect(apple_pay_card.expiration_month.to_i).to be > 0
1429
1499
  expect(apple_pay_card.expiration_year.to_i).to be > 0
1430
- expect(apple_pay_card.source_description).to eq("Visa 2006")
1500
+ expect(apple_pay_card.source_description).to match(/\AVisa \d{4}\z/)
1431
1501
  expect(apple_pay_card.customer_id).to eq(customer.id)
1432
1502
  expect(apple_pay_card.is_device_token).to eq(false)
1433
1503
  apple_pay_card.merchant_token_identifier == "DNITHE302308980427388297"