From 90ace6bad3c76ff0102af16db42c64bab506c01c Mon Sep 17 00:00:00 2001 From: Don Nguyen Date: Tue, 2 Jul 2024 03:15:35 +0700 Subject: [PATCH] [f] Stripe webhook - New configuration to control whether you want to receive test events (#1001) --- .../pay/webhooks/stripe_controller.rb | 3 +- docs/2_configuration.md | 5 ++ lib/pay/stripe.rb | 5 ++ .../pay/webhooks/stripe_controller_test.rb | 75 +++++++++++++++---- test/pay/stripe_test.rb | 15 +++- 5 files changed, 85 insertions(+), 18 deletions(-) diff --git a/app/controllers/pay/webhooks/stripe_controller.rb b/app/controllers/pay/webhooks/stripe_controller.rb index bc718293f..376b27ba8 100644 --- a/app/controllers/pay/webhooks/stripe_controller.rb +++ b/app/controllers/pay/webhooks/stripe_controller.rb @@ -6,7 +6,8 @@ class StripeController < Pay::ApplicationController end def create - queue_event(verified_event) + event = verified_event + queue_event(event) if event.livemode || Pay::Stripe.webhook_receive_test_events head :ok rescue ::Stripe::SignatureVerificationError => e log_error(e) diff --git a/docs/2_configuration.md b/docs/2_configuration.md index 67ccca7e5..fa0d79aba 100644 --- a/docs/2_configuration.md +++ b/docs/2_configuration.md @@ -21,6 +21,7 @@ stripe: private_key: xxxx public_key: yyyy signing_secret: + webhook_receive_test_events: true - aaaa - bbbb braintree: @@ -56,6 +57,7 @@ Pay will also check environment variables for API keys: * `STRIPE_PUBLIC_KEY` * `STRIPE_PRIVATE_KEY` * `STRIPE_SIGNING_SECRET` +* `STRIPE_WEBHOOK_RECEIVE_TEST_EVENTS` * `BRAINTREE_MERCHANT_ID` * `BRAINTREE_PUBLIC_KEY` * `BRAINTREE_PRIVATE_KEY` @@ -71,6 +73,9 @@ Pay will also check environment variables for API keys: * `PADDLE_CLASSIC_PUBLIC_KEY_BASE64` * `PADDLE_CLASSIC_ENVIRONMENT` +#### STRIPE_WEBHOOK_RECEIVE_TEST_EVENTS (Default to TRUE) +As per the guidance from https://support.stripe.com/questions/connect-account-webhook-configurations: "When a connected account is linked solely in live mode to your platform, both live and test events are sent to your live Connect Webhook Endpoint." Therefore, you can set this to false if you wish to receive only live events in Production. + ## Generators If you want to modify the Stripe SCA template or any other views, you can copy over the view files using: diff --git a/lib/pay/stripe.rb b/lib/pay/stripe.rb index 0593ee0b0..f551a3f62 100644 --- a/lib/pay/stripe.rb +++ b/lib/pay/stripe.rb @@ -66,6 +66,11 @@ def self.signing_secret find_value_by_name(:stripe, :signing_secret) end + def self.webhook_receive_test_events + value = find_value_by_name(:stripe, :webhook_receive_test_events) + value.blank? ? true : ActiveModel::Type::Boolean.new.cast(value) + end + def self.configure_webhooks Pay::Webhooks.configure do |events| # Listen to the charge event to make sure we get non-subscription diff --git a/test/controllers/pay/webhooks/stripe_controller_test.rb b/test/controllers/pay/webhooks/stripe_controller_test.rb index 296fc0396..e60326543 100644 --- a/test/controllers/pay/webhooks/stripe_controller_test.rb +++ b/test/controllers/pay/webhooks/stripe_controller_test.rb @@ -14,23 +14,9 @@ class StripeWebhooksControllerTest < ActionDispatch::IntegrationTest end test "should parse a stripe webhook" do - params = { - "id" => "evt_3JMPQbQK2ZHS99Rk0zZhIl7y", - "object" => "event", - "api_version" => "2020-08-27", - "created" => 1628480731, - "data" => fake_event("stripe/charge.succeeded"), - "livemode" => false, - "pending_webhooks" => 3, - "request" => { - "id" => nil, - "idempotency_key" => "in_1JMOTyQK2ZHS99Rk3k06zB02-initial_attempt-0dee959767cdedcc1" - }, - "type" => "charge.succeeded" - } + params = stripe_params(livemode: true) + stripe_event = create_stripe_event(params) - stripe_event = ::Stripe::Event.construct_from(params) - Pay::Webhooks::StripeController.any_instance.expects(:verified_event).returns(stripe_event) ::Stripe::Charge.expects(:retrieve).returns(stripe_event.data.object) pay_customer = pay_customers(:stripe) @@ -47,5 +33,62 @@ class StripeWebhooksControllerTest < ActionDispatch::IntegrationTest perform_enqueued_jobs end end + + test "should not enqueue a job for a test event if webhook_receive_test_events is false" do + with_modified_env("STRIPE_WEBHOOK_RECEIVE_TEST_EVENTS" => "false") do + params = stripe_params(livemode: false) + create_stripe_event(params) + + assert_no_difference "Pay::Webhook.count" do + post webhooks_stripe_path, params: params + assert_response :success + end + end + end + + test "should enqueue a job for a test event if webhook_receive_test_events is true" do + with_modified_env("STRIPE_WEBHOOK_RECEIVE_TEST_EVENTS" => "true") do + params = stripe_params(livemode: false) + create_stripe_event(params) + + assert_difference "Pay::Webhook.count" do + post webhooks_stripe_path, params: params + assert_response :success + end + end + end + + private + + def stripe_params(livemode:) + { + "id" => "evt_3JMPQbQK2ZHS99Rk0zZhIl7y", + "object" => "event", + "api_version" => "2020-08-27", + "created" => 1628480731, + "data" => fake_event("stripe/charge.succeeded"), + "livemode" => livemode, + "pending_webhooks" => 3, + "request" => { + "id" => nil, + "idempotency_key" => "in_1JMOTyQK2ZHS99Rk3k06zB02-initial_attempt-0dee959767cdedcc1" + }, + "type" => "charge.succeeded" + } + end + + def create_stripe_event(params) + stripe_event = ::Stripe::Event.construct_from(params) + Pay::Webhooks::StripeController.any_instance.expects(:verified_event).returns(stripe_event) + stripe_event + end + + def with_modified_env(options, &block) + old_env = ENV.to_hash + ENV.update(options) + yield + ensure + ENV.update(old_env) + end end end diff --git a/test/pay/stripe_test.rb b/test/pay/stripe_test.rb index 50f6a91b3..0be72ec2e 100644 --- a/test/pay/stripe_test.rb +++ b/test/pay/stripe_test.rb @@ -6,12 +6,25 @@ class Pay::Stripe::Test < ActiveSupport::TestCase ENV.update( "STRIPE_PUBLIC_KEY" => "public", "STRIPE_PRIVATE_KEY" => "private", - "STRIPE_SIGNING_SECRET" => "secret" + "STRIPE_SIGNING_SECRET" => "secret", + "STRIPE_WEBHOOK_RECEIVE_TEST_EVENTS" => "false" ) assert_equal "public", Pay::Stripe.public_key assert_equal "private", Pay::Stripe.private_key assert_equal "secret", Pay::Stripe.signing_secret + assert_equal false, Pay::Stripe.webhook_receive_test_events + ensure + ENV.update(old_env) + end + + test "webhook_receive_test_events default to true" do + old_env = ENV.to_hash + ENV.update( + "STRIPE_WEBHOOK_RECEIVE_TEST_EVENTS" => nil + ) + + assert_equal true, Pay::Stripe.webhook_receive_test_events ensure ENV.update(old_env) end