braintree 2.30.0 → 2.30.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -1
  3. data/lib/braintree.rb +5 -1
  4. data/lib/braintree/client_token.rb +18 -0
  5. data/lib/braintree/client_token_gateway.rb +30 -0
  6. data/lib/braintree/configuration.rb +29 -0
  7. data/lib/braintree/credit_card.rb +4 -0
  8. data/lib/braintree/credit_card_gateway.rb +9 -1
  9. data/lib/braintree/customer.rb +4 -0
  10. data/lib/braintree/gateway.rb +4 -0
  11. data/lib/braintree/http.rb +13 -1
  12. data/lib/braintree/sha256_digest.rb +13 -0
  13. data/lib/braintree/signature_service.rb +19 -0
  14. data/lib/braintree/subscription_gateway.rb +2 -0
  15. data/lib/braintree/successful_result.rb +4 -6
  16. data/lib/braintree/transaction_gateway.rb +1 -1
  17. data/lib/braintree/transparent_redirect_gateway.rb +3 -8
  18. data/lib/braintree/version.rb +1 -1
  19. data/lib/braintree/webhook_notification_gateway.rb +11 -5
  20. data/lib/braintree/webhook_testing_gateway.rb +13 -13
  21. data/spec/httpsd.pid +1 -1
  22. data/spec/integration/braintree/client_api/client_token_spec.rb +143 -0
  23. data/spec/integration/braintree/client_api/spec_helper.rb +80 -0
  24. data/spec/integration/braintree/credit_card_spec.rb +99 -0
  25. data/spec/integration/braintree/customer_spec.rb +24 -0
  26. data/spec/integration/braintree/subscription_spec.rb +40 -1
  27. data/spec/integration/braintree/transaction_search_spec.rb +2 -2
  28. data/spec/integration/braintree/transaction_spec.rb +27 -5
  29. data/spec/unit/braintree/client_token_spec.rb +37 -0
  30. data/spec/unit/braintree/configuration_spec.rb +30 -0
  31. data/spec/unit/braintree/credit_card_spec.rb +2 -0
  32. data/spec/unit/braintree/customer_spec.rb +2 -0
  33. data/spec/unit/braintree/digest_spec.rb +14 -0
  34. data/spec/unit/braintree/http_spec.rb +19 -0
  35. data/spec/unit/braintree/sha256_digest_spec.rb +11 -0
  36. data/spec/unit/braintree/signature_service_spec.rb +23 -0
  37. data/spec/unit/braintree/successful_result_spec.rb +7 -7
  38. data/spec/unit/braintree/transparent_redirect_spec.rb +8 -1
  39. data/spec/unit/braintree/webhook_notification_spec.rb +58 -4
  40. metadata +126 -121
@@ -0,0 +1,80 @@
1
+ require 'json'
2
+
3
+ def nonce_for_new_credit_card(options)
4
+ client_token_options = options.delete(:client_token_options) || {}
5
+ client_token = Braintree::ClientToken.generate(client_token_options)
6
+ client = ClientApiHttp.new(Braintree::Configuration.instantiate,
7
+ :authorization_fingerprint => JSON.parse(client_token)["authorizationFingerprint"],
8
+ :shared_customer_identifier => "fake_identifier",
9
+ :shared_customer_identifier_type => "testing"
10
+ )
11
+
12
+ response = client.add_card(options)
13
+ body = JSON.parse(response.body)
14
+
15
+ if body["errors"] != nil
16
+ raise body["errors"].inspect
17
+ end
18
+
19
+ body["nonce"]
20
+ end
21
+
22
+ class ClientApiHttp
23
+ attr_reader :config, :options
24
+
25
+ def initialize(config, options)
26
+ @config = config
27
+ @options = options
28
+ end
29
+
30
+ def get(path)
31
+ _http_do(Net::HTTP::Get, path)
32
+ end
33
+
34
+ def post(path, params)
35
+ _http_do(Net::HTTP::Post, path, params.to_json)
36
+ end
37
+
38
+ def fingerprint=(fingerprint)
39
+ @options[:authorization_fingerprint] = fingerprint
40
+ end
41
+
42
+ def _http_do(http_verb, path, body = nil)
43
+ connection = Net::HTTP.new(@config.server, @config.port)
44
+ connection.read_timeout = 60
45
+ if @config.ssl?
46
+ connection.use_ssl = true
47
+ connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
48
+ connection.ca_file = @config.ca_file
49
+ connection.verify_callback = proc { |preverify_ok, ssl_context| _verify_ssl_certificate(preverify_ok, ssl_context) }
50
+ end
51
+ connection.start do |http|
52
+ request = http_verb.new(path)
53
+ request["X-ApiVersion"] = @config.api_version
54
+ request["Content-Type"] = "application/json"
55
+ request.body = body if body
56
+ http.request(request)
57
+ end
58
+ rescue OpenSSL::SSL::SSLError
59
+ raise Braintree::SSLCertificateError
60
+ end
61
+
62
+ def get_cards
63
+ encoded_fingerprint = Braintree::Util.url_encode(@options[:authorization_fingerprint])
64
+ url = "/merchants/#{@config.merchant_id}/client_api/nonces.json?"
65
+ url += "authorizationFingerprint=#{encoded_fingerprint}"
66
+ url += "&sharedCustomerIdentifier=#{@options[:shared_customer_identifier]}"
67
+ url += "&sharedCustomerIdentifierType=#{@options[:shared_customer_identifier_type]}"
68
+
69
+ get(url)
70
+ end
71
+
72
+ def add_card(params)
73
+ fingerprint = @options[:authorization_fingerprint]
74
+ params[:authorizationFingerprint] = fingerprint
75
+ params[:sharedCustomerIdentifier] = @options[:shared_customer_identifier]
76
+ params[:sharedCustomerIdentifierType] = @options[:shared_customer_identifier_type]
77
+
78
+ post("/merchants/#{@config.merchant_id}/client_api/nonces.json", params)
79
+ end
80
+ end
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
2
3
 
3
4
  describe Braintree::CreditCard do
4
5
  describe "self.create" do
@@ -452,6 +453,30 @@ describe Braintree::CreditCard do
452
453
  end
453
454
  end
454
455
  end
456
+
457
+ context "client API" do
458
+ it "adds credit card to an existing customer using a payment method nonce" do
459
+ nonce = nonce_for_new_credit_card(
460
+ :credit_card => {
461
+ :number => "4111111111111111",
462
+ :expiration_month => "11",
463
+ :expiration_year => "2099",
464
+ },
465
+ :share => true
466
+ )
467
+ customer = Braintree::Customer.create!
468
+ result = Braintree::CreditCard.create(
469
+ :customer_id => customer.id,
470
+ :payment_method_nonce => nonce
471
+ )
472
+
473
+ result.success?.should == true
474
+ credit_card = result.credit_card
475
+ credit_card.bin.should == "411111"
476
+ credit_card.last_4.should == "1111"
477
+ credit_card.expiration_date.should == "11/2099"
478
+ end
479
+ end
455
480
  end
456
481
 
457
482
  describe "self.create!" do
@@ -1138,6 +1163,80 @@ describe Braintree::CreditCard do
1138
1163
  end
1139
1164
  end
1140
1165
 
1166
+ describe "self.from_nonce" do
1167
+ it "finds the payment method with the given nonce" do
1168
+ customer = Braintree::Customer.create!
1169
+ nonce = nonce_for_new_credit_card(
1170
+ :credit_card => {
1171
+ :number => "4111111111111111",
1172
+ :expiration_month => "11",
1173
+ :expiration_year => "2099",
1174
+ },
1175
+ :client_token_options => {:customer_id => customer.id}
1176
+ )
1177
+
1178
+ credit_card = Braintree::CreditCard.from_nonce(nonce)
1179
+ customer = Braintree::Customer.find(customer.id)
1180
+ credit_card.should == customer.credit_cards.first
1181
+ end
1182
+
1183
+ it "does not find a payment method for an unlocked nonce that points to a shared credit card" do
1184
+ nonce = nonce_for_new_credit_card(
1185
+ :credit_card => {
1186
+ :number => "4111111111111111",
1187
+ :expiration_month => "11",
1188
+ :expiration_year => "2099",
1189
+ }
1190
+ )
1191
+ expect do
1192
+ Braintree::CreditCard.from_nonce(nonce)
1193
+ end.to raise_error(Braintree::NotFoundError)
1194
+ end
1195
+
1196
+ it "does not find the payment method for a locked nonce" do
1197
+ client_token = Braintree::ClientToken.generate
1198
+ client = ClientApiHttp.new(Braintree::Configuration.instantiate,
1199
+ :authorization_fingerprint => JSON.parse(client_token)["authorizationFingerprint"],
1200
+ :shared_customer_identifier => "fake_identifier",
1201
+ :shared_customer_identifier_type => "testing"
1202
+ )
1203
+
1204
+ client.add_card(
1205
+ :credit_card => {
1206
+ :number => "4111111111111111",
1207
+ :expiration_month => "11",
1208
+ :expiration_year => "2099",
1209
+ },
1210
+ :share => true
1211
+ )
1212
+
1213
+ response = client.get_cards
1214
+ body = JSON.parse(response.body)
1215
+ nonce = body["creditCards"].first["nonce"]
1216
+
1217
+ expect do
1218
+ Braintree::CreditCard.from_nonce(nonce)
1219
+ end.to raise_error(Braintree::NotFoundError, /locked/)
1220
+ end
1221
+
1222
+ it "does not find the payment method for a consumednonce" do
1223
+ customer = Braintree::Customer.create!
1224
+ nonce = nonce_for_new_credit_card(
1225
+ :credit_card => {
1226
+ :number => "4111111111111111",
1227
+ :expiration_month => "11",
1228
+ :expiration_year => "2099",
1229
+ },
1230
+ :client_token_options => {:customer_id => customer.id}
1231
+ )
1232
+
1233
+ Braintree::CreditCard.from_nonce(nonce)
1234
+ expect do
1235
+ Braintree::CreditCard.from_nonce(nonce)
1236
+ end.to raise_error(Braintree::NotFoundError, /consumed/)
1237
+ end
1238
+ end
1239
+
1141
1240
  describe "self.sale" do
1142
1241
  it "creates a sale transaction using the credit card, returning a result object" do
1143
1242
  customer = Braintree::Customer.create!(
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
  require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
3
+ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
3
4
 
4
5
  describe Braintree::Customer do
5
6
  describe "self.all" do
@@ -379,6 +380,29 @@ describe Braintree::Customer do
379
380
  result.customer.credit_cards.first.venmo_sdk?.should == true
380
381
  end
381
382
  end
383
+
384
+ context "client API" do
385
+ it "can create a customer with a payment method nonce" do
386
+ nonce = nonce_for_new_credit_card(
387
+ :credit_card => {
388
+ :number => "4111111111111111",
389
+ :expiration_month => "11",
390
+ :expiration_year => "2099",
391
+ },
392
+ :share => true
393
+ )
394
+
395
+ result = Braintree::Customer.create(
396
+ :credit_card => {
397
+ :payment_method_nonce => nonce
398
+ }
399
+ )
400
+
401
+ result.success?.should == true
402
+ result.customer.credit_cards.first.bin.should == "411111"
403
+ result.customer.credit_cards.first.last_4.should == "1111"
404
+ end
405
+ end
382
406
  end
383
407
 
384
408
  describe "self.create!" do
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
2
3
 
3
4
  describe Braintree::Subscription do
4
5
 
@@ -63,6 +64,28 @@ describe Braintree::Subscription do
63
64
  result.subscription.id.should == new_id
64
65
  end
65
66
 
67
+ it "creates a subscription when given a payment_method_nonce" do
68
+ nonce = nonce_for_new_credit_card(
69
+ :credit_card => {
70
+ :number => Braintree::Test::CreditCardNumbers::Visa,
71
+ :expiration_month => "11",
72
+ :expiration_year => "2099",
73
+ },
74
+ :client_token_options => {
75
+ :customer_id => @credit_card.customer_id
76
+ }
77
+ )
78
+ result = Braintree::Subscription.create(
79
+ :payment_method_nonce => nonce,
80
+ :plan_id => SpecHelper::TriallessPlan[:id]
81
+ )
82
+
83
+ result.success?.should == true
84
+ transaction = result.subscription.transactions[0]
85
+ transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
86
+ transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4, 4]
87
+ end
88
+
66
89
  context "billing_day_of_month" do
67
90
  it "inherits from the plan if not provided" do
68
91
  result = Braintree::Subscription.create(
@@ -653,7 +676,7 @@ describe Braintree::Subscription do
653
676
  result.subscription.merchant_account_id.should == SpecHelper::NonDefaultMerchantAccountId
654
677
  end
655
678
 
656
- it "allows changing the payment_method_token" do
679
+ it "allows changing the payment method by payment_method_token" do
657
680
  new_credit_card = Braintree::CreditCard.create!(
658
681
  :customer_id => @credit_card.customer_id,
659
682
  :number => Braintree::Test::CreditCardNumbers::Visa,
@@ -667,6 +690,22 @@ describe Braintree::Subscription do
667
690
  result.subscription.payment_method_token.should == new_credit_card.token
668
691
  end
669
692
 
693
+ it "allows changing the payment_method by payment_method_nonce" do
694
+ nonce = nonce_for_new_credit_card(
695
+ :credit_card => {
696
+ :number => Braintree::Test::CreditCardNumbers::MasterCard,
697
+ :expiration_date => "05/2010"
698
+ },
699
+ :client_token_options => {
700
+ :customer_id => @credit_card.customer_id,
701
+ }
702
+ )
703
+
704
+ result = Braintree::Subscription.update(@subscription.id, :payment_method_nonce => nonce)
705
+ result.subscription.transactions[0].credit_card_details.token.should == @credit_card.token
706
+ result.subscription.payment_method_token.should_not == @credit_card.token
707
+ end
708
+
670
709
  it "allows chaning the descriptors" do
671
710
  result = Braintree::Subscription.update(@subscription.id,
672
711
  :descriptor => {
@@ -696,7 +696,7 @@ describe Braintree::Transaction, "search" do
696
696
  context "dispute_date" do
697
697
  it "searches on dispute_date in UTC" do
698
698
  disputed_time = Time.parse("2014-03-01 00:00:00 UTC")
699
- transaction_id = "disputedtransaction"
699
+ transaction_id = "2disputetransaction"
700
700
 
701
701
  collection = Braintree::Transaction.search do |search|
702
702
  search.id.is transaction_id
@@ -746,7 +746,7 @@ describe Braintree::Transaction, "search" do
746
746
 
747
747
  it "searches on dispute_date in local time" do
748
748
  now = Time.parse("2014-03-01 18:00:00 CST")
749
- transaction_id = "disputedtransaction"
749
+ transaction_id = "2disputetransaction"
750
750
 
751
751
  collection = Braintree::Transaction.search do |search|
752
752
  search.id.is transaction_id
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+ require File.expand_path(File.dirname(__FILE__) + "/client_api/spec_helper")
2
3
 
3
4
  describe Braintree::Transaction do
4
5
  describe "self.clone_transaction" do
@@ -1053,6 +1054,27 @@ describe Braintree::Transaction do
1053
1054
  result.transaction.credit_card_details.venmo_sdk?.should == true
1054
1055
  end
1055
1056
  end
1057
+
1058
+ context "client API" do
1059
+ it "can create a transaction with a nonce" do
1060
+ nonce = nonce_for_new_credit_card(
1061
+ :credit_card => {
1062
+ :number => "4111111111111111",
1063
+ :expiration_month => "11",
1064
+ :expiration_year => "2099",
1065
+ },
1066
+ :share => true
1067
+ )
1068
+
1069
+ result = Braintree::Transaction.create(
1070
+ :type => "sale",
1071
+ :amount => Braintree::Test::TransactionAmounts::Authorize,
1072
+ :payment_method_nonce => nonce
1073
+ )
1074
+
1075
+ result.success?.should == true
1076
+ end
1077
+ end
1056
1078
  end
1057
1079
 
1058
1080
  describe "self.create!" do
@@ -1207,7 +1229,7 @@ describe Braintree::Transaction do
1207
1229
  :customer => {
1208
1230
  :first_name => "Dan",
1209
1231
  :last_name => "Smith",
1210
- :company => "Braintree Payment Solutions",
1232
+ :company => "Braintree",
1211
1233
  :email => "dan@example.com",
1212
1234
  :phone => "419-555-1234",
1213
1235
  :fax => "419-555-1235",
@@ -1259,7 +1281,7 @@ describe Braintree::Transaction do
1259
1281
  transaction.cvv_response_code.should == "M"
1260
1282
  transaction.customer_details.first_name.should == "Dan"
1261
1283
  transaction.customer_details.last_name.should == "Smith"
1262
- transaction.customer_details.company.should == "Braintree Payment Solutions"
1284
+ transaction.customer_details.company.should == "Braintree"
1263
1285
  transaction.customer_details.email.should == "dan@example.com"
1264
1286
  transaction.customer_details.phone.should == "419-555-1234"
1265
1287
  transaction.customer_details.fax.should == "419-555-1235"
@@ -1917,7 +1939,7 @@ describe Braintree::Transaction do
1917
1939
  :customer => {
1918
1940
  :first_name => "Dan",
1919
1941
  :last_name => "Smith",
1920
- :company => "Braintree Payment Solutions",
1942
+ :company => "Braintree",
1921
1943
  :email => "dan@example.com",
1922
1944
  :phone => "419-555-1234",
1923
1945
  :fax => "419-555-1235",
@@ -1972,7 +1994,7 @@ describe Braintree::Transaction do
1972
1994
  transaction.cvv_response_code.should == "M"
1973
1995
  transaction.customer_details.first_name.should == "Dan"
1974
1996
  transaction.customer_details.last_name.should == "Smith"
1975
- transaction.customer_details.company.should == "Braintree Payment Solutions"
1997
+ transaction.customer_details.company.should == "Braintree"
1976
1998
  transaction.customer_details.email.should == "dan@example.com"
1977
1999
  transaction.customer_details.phone.should == "419-555-1234"
1978
2000
  transaction.customer_details.fax.should == "419-555-1235"
@@ -2079,7 +2101,7 @@ describe Braintree::Transaction do
2079
2101
  it "includes disputes on found transactions" do
2080
2102
  found_transaction = Braintree::Transaction.find("disputedtransaction")
2081
2103
 
2082
- found_transaction.disputes.count.should == 2
2104
+ found_transaction.disputes.count.should == 1
2083
2105
 
2084
2106
  dispute = found_transaction.disputes.first
2085
2107
  dispute.received_date.should == Date.new(2014, 3, 1)
@@ -0,0 +1,37 @@
1
+
2
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
3
+
4
+ module Braintree
5
+ describe ClientToken do
6
+ describe "self.generate" do
7
+ it "delegates to ClientTokenGateway#generate" do
8
+ options = {:foo => :bar}
9
+ client_token_gateway = double(:client_token_gateway)
10
+ client_token_gateway.should_receive(:generate).with(options).once
11
+ ClientTokenGateway.stub(:new).and_return(client_token_gateway)
12
+ ClientToken.generate(options)
13
+ end
14
+
15
+ it "can't overwrite public_key, or created_at" do
16
+ expect {
17
+ client_token = Braintree::ClientToken.generate(
18
+ :public_key => "bad_key",
19
+ :created_at => "bad_time"
20
+ )
21
+ }.to raise_error(ArgumentError, /created_at, public_key/)
22
+ end
23
+ end
24
+
25
+ context "adding credit_card options with no customer ID" do
26
+ %w(verify_card fail_on_duplicate_payment_method make_default).each do |option_name|
27
+ it "raises an ArgumentError if #{option_name} is present" do
28
+ expect do
29
+ Braintree::ClientToken.generate(
30
+ option_name.to_sym => true
31
+ )
32
+ end.to raise_error(ArgumentError, /#{option_name}/)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -235,6 +235,28 @@ describe Braintree::Configuration do
235
235
  end
236
236
  end
237
237
 
238
+ describe "auth_url" do
239
+ it "is http://auth.venmo.dev for development" do
240
+ Braintree::Configuration.environment = :development
241
+ Braintree::Configuration.instantiate.auth_url.should == "http://auth.venmo.dev:9292"
242
+ end
243
+
244
+ it "is https://auth.venmo.com for production" do
245
+ Braintree::Configuration.environment = :production
246
+ Braintree::Configuration.instantiate.auth_url.should == "https://auth.venmo.com"
247
+ end
248
+
249
+ it "is https://auth.sandbox.venmo.com for sandbox" do
250
+ Braintree::Configuration.environment = :sandbox
251
+ Braintree::Configuration.instantiate.auth_url.should == "https://auth.venmo.sandbox.braintreegateway.com"
252
+ end
253
+
254
+ it "is https://auth.qa.venmo.com for qa" do
255
+ Braintree::Configuration.environment = :qa
256
+ Braintree::Configuration.instantiate.auth_url.should == "https://auth.venmo.qa2.braintreegateway.com"
257
+ end
258
+ end
259
+
238
260
  describe "ssl?" do
239
261
  it "returns false for development" do
240
262
  Braintree::Configuration.environment = :development
@@ -275,4 +297,12 @@ describe Braintree::Configuration do
275
297
  config.inspect.should_not include('secret_key')
276
298
  end
277
299
  end
300
+
301
+ describe "signature_service" do
302
+ it "has a signature service initialized with the private key" do
303
+ config = Braintree::Configuration.new(:private_key => "secret_key")
304
+
305
+ config.signature_service.key.should == "secret_key"
306
+ end
307
+ end
278
308
  end