require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
describe Braintree::WebhookNotification do
describe "self.sample_notification" do
it "builds a sample notification and signature given an identifier and kind" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::SubscriptionWentPastDue
notification.subscription.id.should == "my_id"
notification.timestamp.should be_within(10).of(Time.now.utc)
end
it "builds a sample notification for a partner merchant connected webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::PartnerMerchantConnected,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::PartnerMerchantConnected
notification.partner_merchant.merchant_public_id.should == "public_id"
notification.partner_merchant.public_key.should == "public_key"
notification.partner_merchant.private_key.should == "private_key"
notification.partner_merchant.partner_merchant_id.should == "abc123"
notification.partner_merchant.client_side_encryption_key.should == "cse_key"
notification.timestamp.should be_within(10).of(Time.now.utc)
end
it "builds a sample notification for a partner merchant disconnected webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::PartnerMerchantDisconnected,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::PartnerMerchantDisconnected
notification.partner_merchant.partner_merchant_id.should == "abc123"
notification.timestamp.should be_within(10).of(Time.now.utc)
end
it "builds a sample notification for a partner merchant declined webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::PartnerMerchantDeclined,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::PartnerMerchantDeclined
notification.partner_merchant.partner_merchant_id.should == "abc123"
notification.timestamp.should be_within(10).of(Time.now.utc)
end
it "builds a sample notification with a source merchant ID" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
"my_id",
"my_source_merchant_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.source_merchant_id.should == "my_source_merchant_id"
end
it "doesn't include source merchant IDs if not supplied" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::PartnerMerchantDeclined,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.source_merchant_id.should be_nil
end
context "auth" do
it "builds a sample notification for a status transitioned webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::ConnectedMerchantStatusTransitioned,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::ConnectedMerchantStatusTransitioned
status_transitioned = notification.connected_merchant_status_transitioned
status_transitioned.merchant_public_id.should == "my_id"
status_transitioned.merchant_id.should == "my_id"
status_transitioned.oauth_application_client_id.should == "oauth_application_client_id"
status_transitioned.status.should == "new_status"
end
it "builds a sample notification for a paypal status changed webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::ConnectedMerchantPayPalStatusChanged,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::ConnectedMerchantPayPalStatusChanged
paypal_status_changed = notification.connected_merchant_paypal_status_changed
paypal_status_changed.merchant_public_id.should == "my_id"
paypal_status_changed.merchant_id.should == "my_id"
paypal_status_changed.oauth_application_client_id.should == "oauth_application_client_id"
paypal_status_changed.action.should == "link"
end
it 'builds a sample notification for OAuth application revocation' do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::OAuthAccessRevoked,
'my_id'
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::OAuthAccessRevoked
notification.oauth_access_revocation.merchant_id.should == "my_id"
notification.oauth_access_revocation.oauth_application_client_id.should == "oauth_application_client_id"
notification.timestamp.should be_within(10).of(Time.now.utc)
end
end
context "disputes" do
let(:dispute_id) { "my_id" }
shared_examples "dispute webhooks" do
it "builds a sample notification for a dispute opened webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::DisputeOpened,
dispute_id
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::DisputeOpened
dispute = notification.dispute
dispute.status.should == Braintree::Dispute::Status::Open
dispute.id.should == dispute_id
dispute.kind.should == Braintree::Dispute::Kind::Chargeback
end
it "builds a sample notification for a dispute lost webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::DisputeLost,
dispute_id
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::DisputeLost
dispute = notification.dispute
dispute.status.should == Braintree::Dispute::Status::Lost
dispute.id.should == dispute_id
dispute.kind.should == Braintree::Dispute::Kind::Chargeback
end
it "builds a sample notification for a dispute won webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::DisputeWon,
dispute_id
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::DisputeWon
dispute = notification.dispute
dispute.status.should == Braintree::Dispute::Status::Won
dispute.id.should == dispute_id
dispute.kind.should == Braintree::Dispute::Kind::Chargeback
end
it "is compatible with the previous dispute won webhook interface" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::DisputeWon,
dispute_id
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::DisputeWon
dispute = notification.dispute
dispute.amount.should == 100.00
dispute.id.should == dispute_id
dispute.date_opened.should == Date.new(2014, 3, 21)
dispute.date_won.should == Date.new(2014, 3, 22)
dispute.transaction_details.amount.should == 100.00
dispute.transaction_details.id.should == dispute_id
end
end
context "older webhooks" do
let(:dispute_id) { "legacy_dispute_id" }
include_examples "dispute webhooks"
end
context "newer webhooks" do
include_examples "dispute webhooks"
end
end
context "disbursement" do
it "builds a sample notification for a transaction disbursed webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::TransactionDisbursed,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::TransactionDisbursed
notification.transaction.id.should == "my_id"
notification.transaction.amount.should == 1_00
notification.transaction.disbursement_details.disbursement_date.should == "2013-07-09"
end
it "builds a sample notification for a disbursement_exception webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::DisbursementException,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::DisbursementException
notification.disbursement.id.should == "my_id"
notification.disbursement.transaction_ids.should == %W{ afv56j kj8hjk }
notification.disbursement.retry.should be(false)
notification.disbursement.success.should be(false)
notification.disbursement.exception_message.should == "bank_rejected"
notification.disbursement.disbursement_date.should == Date.parse("2014-02-10")
notification.disbursement.follow_up_action.should == "update_funding_information"
notification.disbursement.merchant_account.id.should == "merchant_account_token"
end
it "builds a sample notification for a disbursement webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::Disbursement,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::Disbursement
notification.disbursement.id.should == "my_id"
notification.disbursement.transaction_ids.should == %W{ afv56j kj8hjk }
notification.disbursement.retry.should be(false)
notification.disbursement.success.should be(true)
notification.disbursement.exception_message.should be_nil
notification.disbursement.disbursement_date.should == Date.parse("2014-02-10")
notification.disbursement.follow_up_action.should be_nil
notification.disbursement.merchant_account.id.should == "merchant_account_token"
end
end
context "us bank account transactions" do
it "builds a sample notification for a settlement webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::TransactionSettled,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::TransactionSettled
notification.transaction.status.should == "settled"
notification.transaction.us_bank_account_details.account_type.should == "checking"
notification.transaction.us_bank_account_details.account_holder_name.should == "Dan Schulman"
notification.transaction.us_bank_account_details.routing_number.should == "123456789"
notification.transaction.us_bank_account_details.last_4.should == "1234"
end
it "builds a sample notification for a settlement declined webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::TransactionSettlementDeclined,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::TransactionSettlementDeclined
notification.transaction.status.should == "settlement_declined"
notification.transaction.us_bank_account_details.account_type.should == "checking"
notification.transaction.us_bank_account_details.account_holder_name.should == "Dan Schulman"
notification.transaction.us_bank_account_details.routing_number.should == "123456789"
notification.transaction.us_bank_account_details.last_4.should == "1234"
end
end
context "merchant account" do
it "builds a sample notification for a merchant account approved webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubMerchantAccountApproved,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::SubMerchantAccountApproved
notification.merchant_account.id.should == "my_id"
notification.merchant_account.status.should == Braintree::MerchantAccount::Status::Active
notification.merchant_account.master_merchant_account.id.should == "master_ma_for_my_id"
notification.merchant_account.master_merchant_account.status.should == Braintree::MerchantAccount::Status::Active
end
it "builds a sample notification for a merchant account declined webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubMerchantAccountDeclined,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::SubMerchantAccountDeclined
notification.merchant_account.id.should == "my_id"
notification.merchant_account.status.should == Braintree::MerchantAccount::Status::Suspended
notification.merchant_account.master_merchant_account.id.should == "master_ma_for_my_id"
notification.merchant_account.master_merchant_account.status.should == Braintree::MerchantAccount::Status::Suspended
notification.message.should == "Credit score is too low"
notification.errors.for(:merchant_account).on(:base).first.code.should == Braintree::ErrorCodes::MerchantAccount::DeclinedOFAC
end
end
context "subscription" do
it "builds a sample notification for a subscription charged successfully webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionChargedSuccessfully,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::SubscriptionChargedSuccessfully
notification.subscription.id.should == "my_id"
notification.subscription.transactions.size.should == 1
notification.subscription.transactions.first.status.should == Braintree::Transaction::Status::SubmittedForSettlement
notification.subscription.transactions.first.amount.should == BigDecimal("49.99")
end
it "builds a sample notification for a subscription charged unsuccessfully webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionChargedUnsuccessfully,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::SubscriptionChargedUnsuccessfully
notification.subscription.id.should == "my_id"
notification.subscription.transactions.size.should == 1
notification.subscription.transactions.first.status.should == Braintree::Transaction::Status::Failed
notification.subscription.transactions.first.amount.should == BigDecimal("49.99")
end
end
it "includes a valid signature" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
"my_id"
)
expected_signature = Braintree::Digest.hexdigest(Braintree::Configuration.private_key, sample_notification[:bt_payload])
sample_notification[:bt_signature].should == "#{Braintree::Configuration.public_key}|#{expected_signature}"
end
end
context "account_updater_daily_report" do
it "builds a sample notification for an account_updater_daily_report webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::AccountUpdaterDailyReport,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::AccountUpdaterDailyReport
notification.account_updater_daily_report.report_url.should == "link-to-csv-report"
notification.account_updater_daily_report.report_date.should == Date.parse("2016-01-14")
end
end
context "granted_payment_instrument_update" do
it "builds a sample notification for a GrantorUpdatedGrantedPaymentMethod webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::GrantorUpdatedGrantedPaymentMethod,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
update = notification.granted_payment_instrument_update
notification.kind.should == Braintree::WebhookNotification::Kind::GrantorUpdatedGrantedPaymentMethod
update.grant_owner_merchant_id.should == 'vczo7jqrpwrsi2px'
update.grant_recipient_merchant_id.should == 'cf0i8wgarszuy6hc'
update.payment_method_nonce.should == 'ee257d98-de40-47e8-96b3-a6954ea7a9a4'
update.token.should == 'abc123z'
update.updated_fields.should == ['expiration-month', 'expiration-year']
end
it "builds a sample notification for a RecipientUpdatedGrantedPaymentMethod webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::RecipientUpdatedGrantedPaymentMethod,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
update = notification.granted_payment_instrument_update
notification.kind.should == Braintree::WebhookNotification::Kind::RecipientUpdatedGrantedPaymentMethod
update.grant_owner_merchant_id.should == 'vczo7jqrpwrsi2px'
update.grant_recipient_merchant_id.should == 'cf0i8wgarszuy6hc'
update.payment_method_nonce.should == 'ee257d98-de40-47e8-96b3-a6954ea7a9a4'
update.token.should == 'abc123z'
update.updated_fields.should == ['expiration-month', 'expiration-year']
end
end
context "granted_payment_instrument_revoked" do
let(:gateway) do
config = Braintree::Configuration.new(
:merchant_id => 'merchant_id',
:public_key => 'wrong_public_key',
:private_key => 'wrong_private_key'
)
Braintree::Gateway.new(config)
end
describe "credit cards" do
it "builds a webhook notification for a granted_payment_instrument_revoked webhook" do
webhook_xml_response = <<-XML
12345
2018-10-10T22:46:41Z
granted_payment_instrument_revoked
555555
MasterCard
Amber Ankunding
Unknown
Unknown
2018-10-10T22:46:41Z
credit_card_customer_id
US
Unknown
true
Unknown
06
2020
false
cGF5bWVudG1ldGhvZF8zcHQ2d2hz
Unknown
https://assets.braintreegateway.com/payment_method_logo/mastercard.png?environment=test
Unknown
4444
Unknown
Unknown
Unknown
credit_card_token
08199d188e37460163207f714faf074a
2018-10-10T22:46:41Z
false
XML
attributes = Braintree::Xml.hash_from_xml(webhook_xml_response)
notification = Braintree::WebhookNotification._new(gateway, attributes[:notification])
metadata = notification.revoked_payment_method_metadata
notification.kind.should == Braintree::WebhookNotification::Kind::GrantedPaymentInstrumentRevoked
metadata.customer_id.should == "credit_card_customer_id"
metadata.token.should == "credit_card_token"
metadata.revoked_payment_method.class.should == Braintree::CreditCard
end
end
describe "paypal accounts" do
it "builds a webhook notification for a granted_payment_instrument_revoked webhook" do
webhook_xml_response = <<-XML
12345
2018-10-10T22:46:41Z
granted_payment_instrument_revoked
billing_agreement_id
2018-10-11T21:10:33Z
paypal_customer_id
true
johndoe@example.com
cGF5bWVudG1ldGhvZF9wYXlwYWxfdG9rZW4
https://jsdk.bt.local:9000/payment_method_logo/paypal.png?environment=test://assets.braintreegateway.com/payment_method_logo/paypal.png?environment=test
paypal_token
2018-10-11T21:10:33Z
a6a8e1a4
XML
attributes = Braintree::Xml.hash_from_xml(webhook_xml_response)
notification = Braintree::WebhookNotification._new(gateway, attributes[:notification])
metadata = notification.revoked_payment_method_metadata
notification.kind.should == Braintree::WebhookNotification::Kind::GrantedPaymentInstrumentRevoked
metadata.customer_id.should == "paypal_customer_id"
metadata.token.should == "paypal_token"
metadata.revoked_payment_method.class.should == Braintree::PayPalAccount
end
end
describe "venmo accounts" do
it "builds a webhook notification for a granted_payment_instrument_revoked webhook" do
webhook_xml_response = <<-XML
12345
2018-10-10T22:46:41Z
granted_payment_instrument_revoked
2018-10-11T21:28:37Z
2018-10-11T21:28:37Z
true
https://assets.braintreegateway.com/payment_method_logo/venmo.png?environment=test
venmo_token
Venmo Account: venmojoe
venmojoe
456
venmo_customer_id
cGF5bWVudG1ldGhvZF92ZW5tb2FjY291bnQ
XML
attributes = Braintree::Xml.hash_from_xml(webhook_xml_response)
notification = Braintree::WebhookNotification._new(gateway, attributes[:notification])
metadata = notification.revoked_payment_method_metadata
notification.kind.should == Braintree::WebhookNotification::Kind::GrantedPaymentInstrumentRevoked
metadata.customer_id.should == "venmo_customer_id"
metadata.token.should == "venmo_token"
metadata.revoked_payment_method.class.should == Braintree::VenmoAccount
end
end
end
context "payment_method_revoked_by_customer" do
it "builds a sample notification for a payment_method_revoked_by_customer webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::PaymentMethodRevokedByCustomer,
"my_payment_method_token"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::PaymentMethodRevokedByCustomer
metadata = notification.revoked_payment_method_metadata
metadata.token.should == "my_payment_method_token"
metadata.revoked_payment_method.class.should == Braintree::PayPalAccount
metadata.revoked_payment_method.revoked_at.should_not be_nil
end
end
context "local_payment_completed" do
it "builds a sample notification for a local_payment webhook" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::LocalPaymentCompleted,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
notification.kind.should == Braintree::WebhookNotification::Kind::LocalPaymentCompleted
local_payment_completed = notification.local_payment_completed
local_payment_completed.payment_id.should == "PAY-XYZ123"
local_payment_completed.payer_id.should == "ABCPAYER"
local_payment_completed.payment_method_nonce.should == "ee257d98-de40-47e8-96b3-a6954ea7a9a4"
local_payment_completed.transaction.id.should == "my_id"
local_payment_completed.transaction.status.should == Braintree::Transaction::Status::Authorized
local_payment_completed.transaction.amount.should == 49.99
local_payment_completed.transaction.order_id.should == "order4567"
end
end
describe "parse" do
it "raises InvalidSignature error when the signature is nil" do
expect do
Braintree::WebhookNotification.parse(nil, "payload")
end.to raise_error(Braintree::InvalidSignature, "signature cannot be nil")
end
it "raises InvalidSignature error when the payload is nil" do
expect do
Braintree::WebhookNotification.parse("signature", nil)
end.to raise_error(Braintree::InvalidSignature, "payload cannot be nil")
end
it "raises InvalidSignature error when the signature is completely invalid" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
"my_id"
)
expect do
Braintree::WebhookNotification.parse("not a valid signature", sample_notification[:bt_payload])
end.to raise_error(Braintree::InvalidSignature)
end
it "raises InvalidSignature error with a message when the public key is not found" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
"my_id"
)
config = Braintree::Configuration.new(
:merchant_id => 'merchant_id',
:public_key => 'wrong_public_key',
:private_key => 'wrong_private_key'
)
gateway = Braintree::Gateway.new(config)
expect do
gateway.webhook_notification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
end.to raise_error(Braintree::InvalidSignature, /no matching public key/)
end
it "raises InvalidSignature error if the payload has been changed" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
"my_id"
)
expect do
Braintree::WebhookNotification.parse(sample_notification[:bt_signature], "badstuff" + sample_notification[:bt_payload])
end.to raise_error(Braintree::InvalidSignature, /signature does not match payload - one has been modified/)
end
it "raises InvalidSignature error with a message complaining about invalid characters" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
"my_id"
)
expect do
Braintree::WebhookNotification.parse(sample_notification[:bt_signature], "^& bad ,* chars @!" + sample_notification[:bt_payload])
end.to raise_error(Braintree::InvalidSignature, /payload contains illegal characters/)
end
it "allows all valid characters" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
"my_id"
)
sample_notification[:bt_payload] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+=/\n"
begin
Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload])
rescue Braintree::InvalidSignature => e
exception = e
end
exception.message.should_not match(/payload contains illegal characters/)
end
it "retries a payload with a newline" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
"my_id"
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload].rstrip)
notification.kind.should == Braintree::WebhookNotification::Kind::SubscriptionWentPastDue
notification.subscription.id.should == "my_id"
notification.timestamp.should be_within(10).of(Time.now.utc)
end
end
describe "check?" do
it "returns true for check webhook kinds" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::Check,
nil
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload].rstrip)
notification.check?.should == true
end
it "returns false for non-check webhook kinds" do
sample_notification = Braintree::WebhookTesting.sample_notification(
Braintree::WebhookNotification::Kind::SubscriptionWentPastDue,
nil
)
notification = Braintree::WebhookNotification.parse(sample_notification[:bt_signature], sample_notification[:bt_payload].rstrip)
notification.check?.should == false
end
end
describe "self.verify" do
it "creates a verification string" do
response = Braintree::WebhookNotification.verify("20f9f8ed05f77439fe955c977e4c8a53")
response.should == "integration_public_key|d9b899556c966b3f06945ec21311865d35df3ce4"
end
it "raises InvalidChallenge error with a message complaining about invalid characters" do
challenge = "bad challenge"
expect do
Braintree::WebhookNotification.verify(challenge)
end.to raise_error(Braintree::InvalidChallenge, /challenge contains non-hex characters/)
end
end
end