diff --git a/CHANGELOG.md b/CHANGELOG.md index fad3711e..7ca02e77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 4.4.0 +* Sanitize encrypted_card_data logs +* Add `LocalPaymentExpired` and `LocalPaymentFunded` webhook notification support + ## 4.3.0 * Add a log message to the `ArgumentError` at `TransactionGateway.find` * Add `exchange_rate_quote_id` to `Transaction.create` diff --git a/lib/braintree.rb b/lib/braintree.rb index e9fafb1f..680a7784 100644 --- a/lib/braintree.rb +++ b/lib/braintree.rb @@ -73,6 +73,8 @@ require "braintree/google_pay_card" require "braintree/local_payment_completed" require "braintree/local_payment_reversed" +require "braintree/local_payment_expired" +require "braintree/local_payment_funded" require "braintree/transaction/local_payment_details" require "braintree/merchant" require "braintree/merchant_gateway" diff --git a/lib/braintree/http.rb b/lib/braintree/http.rb index 82d70e3c..5439d113 100644 --- a/lib/braintree/http.rb +++ b/lib/braintree/http.rb @@ -188,6 +188,7 @@ def _format_and_sanitize_body_for_log(input_xml) formatted_xml = input_xml.gsub(/^/, "[Braintree] ") formatted_xml = formatted_xml.gsub(/(.{6}).+?(.{4})<\/number>/m, '\1******\2') formatted_xml = formatted_xml.gsub(/.+?<\/cvv>/m, "***") + formatted_xml = formatted_xml.gsub(/.+?<\/encrypted-card-data>/m, "***") formatted_xml end diff --git a/lib/braintree/local_payment_expired.rb b/lib/braintree/local_payment_expired.rb new file mode 100644 index 00000000..1b4213de --- /dev/null +++ b/lib/braintree/local_payment_expired.rb @@ -0,0 +1,21 @@ +module Braintree + class LocalPaymentExpired + include BaseModule + + attr_reader :payment_id + attr_reader :payment_context_id + + def initialize(attributes) # :nodoc: + set_instance_variables_from_hash(attributes) + end + + class << self + protected :new + end + + def self._new(*args) # :nodoc: + self.new(*args) + end + end +end + diff --git a/lib/braintree/local_payment_funded.rb b/lib/braintree/local_payment_funded.rb new file mode 100644 index 00000000..7ba8fbad --- /dev/null +++ b/lib/braintree/local_payment_funded.rb @@ -0,0 +1,22 @@ +module Braintree + class LocalPaymentFunded + include BaseModule + + attr_reader :payment_id + attr_reader :payment_context_id + attr_reader :transaction + + def initialize(attributes) # :nodoc: + set_instance_variables_from_hash(attributes) + @transaction = Transaction._new(Configuration.gateway, transaction) + end + + class << self + protected :new + end + + def self._new(*args) # :nodoc: + self.new(*args) + end + end +end diff --git a/lib/braintree/version.rb b/lib/braintree/version.rb index b1f12801..48f9066a 100644 --- a/lib/braintree/version.rb +++ b/lib/braintree/version.rb @@ -1,7 +1,7 @@ module Braintree module Version Major = 4 - Minor = 3 + Minor = 4 Tiny = 0 String = "#{Major}.#{Minor}.#{Tiny}" diff --git a/lib/braintree/webhook_notification.rb b/lib/braintree/webhook_notification.rb index 07f7a5bb..3411f635 100644 --- a/lib/braintree/webhook_notification.rb +++ b/lib/braintree/webhook_notification.rb @@ -28,6 +28,8 @@ module Kind GrantedPaymentMethodRevoked = "granted_payment_method_revoked" LocalPaymentCompleted = "local_payment_completed" + LocalPaymentExpired = "local_payment_expired" + LocalPaymentFunded = "local_payment_funded" LocalPaymentReversed = "local_payment_reversed" OAuthAccessRevoked = "oauth_access_revoked" @@ -65,6 +67,8 @@ module Kind attr_reader :revoked_payment_method_metadata attr_reader :kind attr_reader :local_payment_completed + attr_reader :local_payment_expired + attr_reader :local_payment_funded attr_reader :local_payment_reversed attr_reader :oauth_access_revocation attr_reader :partner_merchant @@ -98,6 +102,8 @@ def initialize(gateway, attributes) # :nodoc: @granted_payment_instrument_update = GrantedPaymentInstrumentUpdate._new(@subject[:granted_payment_instrument_update]) if @subject.has_key?(:granted_payment_instrument_update) @revoked_payment_method_metadata = RevokedPaymentMethodMetadata._new(gateway, @subject) if [Kind::GrantedPaymentInstrumentRevoked, Kind::PaymentMethodRevokedByCustomer, Kind::GrantedPaymentMethodRevoked].include?(@kind) @local_payment_completed = LocalPaymentCompleted._new(@subject[:local_payment]) if @subject.has_key?(:local_payment) && Kind::LocalPaymentCompleted == @kind + @local_payment_expired = LocalPaymentExpired._new(@subject[:local_payment_expired]) if @subject.has_key?(:local_payment_expired) && Kind::LocalPaymentExpired == @kind + @local_payment_funded = LocalPaymentFunded._new(@subject[:local_payment_funded]) if @subject.has_key?(:local_payment_funded) && Kind::LocalPaymentFunded == @kind @local_payment_reversed = LocalPaymentReversed._new(@subject[:local_payment_reversed]) if @subject.has_key?(:local_payment_reversed) && Kind::LocalPaymentReversed == @kind end diff --git a/lib/braintree/webhook_testing_gateway.rb b/lib/braintree/webhook_testing_gateway.rb index 779929c7..cd25ec0e 100644 --- a/lib/braintree/webhook_testing_gateway.rb +++ b/lib/braintree/webhook_testing_gateway.rb @@ -88,8 +88,12 @@ def _subject_sample_xml(kind, id) _payment_method_revoked_by_customer_sample_xml(id) when Braintree::WebhookNotification::Kind::LocalPaymentCompleted _local_payment_completed_sample_xml(id) + when Braintree::WebhookNotification::Kind::LocalPaymentExpired + _local_payment_expired_sample_xml + when Braintree::WebhookNotification::Kind::LocalPaymentFunded + _local_payment_funded_sample_xml(id) when Braintree::WebhookNotification::Kind::LocalPaymentReversed - _local_payment_reversed_sample_xml(id) + _local_payment_reversed_sample_xml else _subscription_sample_xml(id) end @@ -935,10 +939,35 @@ def _local_payment_completed_sample_xml(id) XML end - def _local_payment_reversed_sample_xml(id) + def _local_payment_expired_sample_xml + <<-XML + + PAY-XYZ123 + cG5b= + + XML + end + + def _local_payment_funded_sample_xml(id) + <<-XML + + PAY-XYZ123 + cG5b= + + #{id} + settled + 49.99 + order4567 + + + XML + end + + def _local_payment_reversed_sample_xml <<-XML PAY-XYZ123 + cG5b= XML end diff --git a/spec/unit/braintree/http_spec.rb b/spec/unit/braintree/http_spec.rb index bc555e62..caed7a01 100644 --- a/spec/unit/braintree/http_spec.rb +++ b/spec/unit/braintree/http_spec.rb @@ -25,6 +25,7 @@ Doe 1234560000001234 123 + 8F34DFB312DC79C24FD5320622F3E11682D79E6B0C0FD881 END @@ -34,6 +35,7 @@ [Braintree] Doe [Braintree] 123456******1234 [Braintree] *** +[Braintree] *** [Braintree] END Braintree::Http.new(:config)._format_and_sanitize_body_for_log(input_xml).should == expected_xml diff --git a/spec/unit/braintree/local_payment_expired_spec.rb b/spec/unit/braintree/local_payment_expired_spec.rb new file mode 100644 index 00000000..2520c297 --- /dev/null +++ b/spec/unit/braintree/local_payment_expired_spec.rb @@ -0,0 +1,24 @@ +require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") + +describe Braintree::LocalPaymentExpired do + describe "self.new" do + it "is protected" do + expect do + Braintree::LocalPaymentExpired.new + end.to raise_error(NoMethodError, /protected method .new/) + end + end + + describe "self._new" do + it "initializes the object with the appropriate attributes set" do + params = { + payment_id: "a-payment-id", + payment_context_id: "a-payment-context-id", + } + local_payment_expired = Braintree::LocalPaymentExpired._new(params) + + local_payment_expired.payment_id.should eq("a-payment-id") + local_payment_expired.payment_context_id.should eq("a-payment-context-id") + end + end +end diff --git a/spec/unit/braintree/local_payment_funded_spec.rb b/spec/unit/braintree/local_payment_funded_spec.rb new file mode 100644 index 00000000..7a62a092 --- /dev/null +++ b/spec/unit/braintree/local_payment_funded_spec.rb @@ -0,0 +1,34 @@ +require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") + +describe Braintree::LocalPaymentFunded do + describe "self.new" do + it "is protected" do + expect do + Braintree::LocalPaymentFunded.new + end.to raise_error(NoMethodError, /protected method .new/) + end + end + + describe "self._new" do + it "initializes the object with the appropriate attributes set" do + params = { + payment_id: "a-payment-id", + payment_context_id: "a-payment-context-id", + transaction: { + id: "a-transaction-id", + amount: "31.00", + order_id: "an-order-id", + status: Braintree::Transaction::Status::Settled, + }, + } + local_payment_funded = Braintree::LocalPaymentFunded._new(params) + + local_payment_funded.payment_id.should eq("a-payment-id") + local_payment_funded.payment_context_id.should eq("a-payment-context-id") + local_payment_funded.transaction.id.should eq("a-transaction-id") + local_payment_funded.transaction.amount.should eq(31.0) + local_payment_funded.transaction.order_id.should eq("an-order-id") + local_payment_funded.transaction.status.should eq(Braintree::Transaction::Status::Settled) + end + end +end diff --git a/spec/unit/braintree/webhook_notification_spec.rb b/spec/unit/braintree/webhook_notification_spec.rb index 7d41714c..dcfa39fe 100644 --- a/spec/unit/braintree/webhook_notification_spec.rb +++ b/spec/unit/braintree/webhook_notification_spec.rb @@ -668,6 +668,40 @@ end end + context "local_payment_expired" do + it "builds a sample notification for a local_payment_expired webhook" do + sample_notification = Braintree::WebhookTesting.sample_notification( + Braintree::WebhookNotification::Kind::LocalPaymentExpired, + "my_id", + ) + + notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload]) + notification.kind.should == Braintree::WebhookNotification::Kind::LocalPaymentExpired + + local_payment_expired = notification.local_payment_expired + local_payment_expired.payment_id.should == "PAY-XYZ123" + local_payment_expired.payment_context_id.should == "cG5b=" + end + end + + context "local_payment_funded" do + it "builds a sample notification for a local_payment_funded webhook" do + sample_notification = Braintree::WebhookTesting.sample_notification( + Braintree::WebhookNotification::Kind::LocalPaymentFunded, + "my_id", + ) + notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload]) + notification.kind.should == Braintree::WebhookNotification::Kind::LocalPaymentFunded + + local_payment_funded = notification.local_payment_funded + local_payment_funded.payment_id.should == "PAY-XYZ123" + local_payment_funded.payment_context_id.should == "cG5b=" + local_payment_funded.transaction.id.should == "my_id" + local_payment_funded.transaction.status.should == Braintree::Transaction::Status::Settled + local_payment_funded.transaction.amount.should == 49.99 + local_payment_funded.transaction.order_id.should == "order4567" + end + end context "local_payment_reversed" do it "builds a sample notification for a local_payment webhook" do @@ -675,7 +709,6 @@ Braintree::WebhookNotification::Kind::LocalPaymentReversed, "my_id", ) - notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload]) notification.kind.should == Braintree::WebhookNotification::Kind::LocalPaymentReversed