Add Stripe webhook signature verification

This commit is contained in:
Nathan Chapman 2023-01-22 14:16:06 -07:00
parent e7c451360e
commit 0546c18183
4 changed files with 25 additions and 82 deletions

View File

@ -17,7 +17,7 @@ server {
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ptcoffee.com;
server_name ptcoffee.com www.ptcoffee.com;
# SSL
ssl_certificate /etc/letsencrypt/live/ptcoffee.com/fullchain.pem;

View File

@ -272,6 +272,7 @@ FACEBOOK_PIXEL_ID = env('FACEBOOK_PIXEL_ID', '')
# https://stripe.com/docs
STRIPE_API_KEY = env('STRIPE_API_KEY')
STRIPE_WEBHOOK_SECRET = env('STRIPE_WEBHOOK_SECRET', None)
# PayPal

View File

@ -271,6 +271,7 @@ class Cart:
validation.result['RateV4Response']['Package']['Postage']
)
except KeyError:
logger.warning(validation.result)
raise USPSPostageError(
'Could not retrieve postage.'
)

View File

@ -721,108 +721,49 @@ class SubscriptionDoneView(TemplateView):
def stripe_webhook(request):
# You can use webhooks to receive information about asynchronous payment events.
# For more about our webhook events check out https://stripe.com/docs/webhooks.
webhook_secret = None
request_data = json.loads(request.body)
endpoint_secret = settings.STRIPE_WEBHOOK_SECRET
payload = request.body
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
event = None
if webhook_secret:
# Retrieve the event by verifying the signature using the raw body
# and secret if webhook signing is configured.
signature = request.headers.get('stripe-signature')
try:
event = stripe.Webhook.construct_event(
payload=request.data, sig_header=signature, secret=webhook_secret)
data = event['data']
except Exception as e:
return e
# Get the type of webhook event sent - used to check the status
# of PaymentIntents.
event_type = event['type']
else:
data = request_data['data']
event_type = request_data['type']
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError as e:
# Invalid payload
logger.warning('Stripe Webhook: Invalid payload')
return JsonResponse({'status': 'ERROR: Invalid payload'})
except stripe.error.SignatureVerificationError as e:
# Invalid signature
logger.warning('Stripe Webhook: Invalid signature')
return JsonResponse({'status': 'ERROR: Invalid signature'})
data_object = data['object']
# logger.warning('\n')
# logger.warning(event_type.upper() + ':\n')
# logger.warning(data)
# logger.warning('\n')
if event_type == 'checkout.session.completed':
# Payment is successful and the subscription is created.
# You should provision the subscription and save the customer ID to your database.
pass
if event_type == 'customer.subscription.created':
if event.type == 'customer.subscription.created':
try:
subscription = Subscription.objects.get(
pk=data_object['metadata'].get('subscription_pk')
pk=event.data.object['metadata'].get('subscription_pk')
)
except Subscription.DoesNotExist:
logger.warning('Subscription does not exist')
raise
else:
subscription.stripe_id = data_object['id']
subscription.stripe_id = event.data.object['id']
subscription.is_active = True
subscription.save()
if event_type == 'invoice.paid':
if event.type == 'invoice.paid':
# Continue to provision the subscription as payments continue to be made.
# Store the status in your database and check when a user accesses your service.
# This approach helps you avoid hitting rate limits.
try:
subscription = Subscription.objects.get(
stripe_id=data_object['subscription']
stripe_id=event.data.object['subscription']
)
except Subscription.DoesNotExist:
logger.warning('Subscription does not exist')
raise
else:
subscription.create_order(data_object)
if event_type == 'invoice.payment_failed':
# The payment failed or the customer does not have a valid payment method.
# The subscription becomes past_due. Notify your customer and send them to the
# customer portal to update their payment information.
pass
if event_type == 'invoice.created':
# Add shipping cost as an item on the invoice
# shipping_cost = get_shipping_cost(
# self.object.total_weight,
# self.request.user.default_shipping_address.postal_code
# ) * 100
# stripe.InvoiceItem.create(
# customer=data_object['customer'],
# subscription=data_object['subscription'],
# description='Shipping',
# unit_amount=1234,
# currency=settings.DEFAULT_CURRENCY.lower()
# )
pass
# # if event_type == 'checkout.session.completed':
# if event_type == 'invoice.paid':
# # Used to provision services after the trial has ended.
# # The status of the invoice will show up as paid. Store the status in your
# # database to reference when a user accesses your service to avoid hitting rate
# # limits.
# messages.success(request, 'Paid')
# logger.warning(data)
# if event_type == 'invoice.payment_failed':
# # If the payment fails or the customer does not have a valid payment method,
# # an invoice.payment_failed event is sent, the subscription becomes past_due.
# # Use this webhook to notify your user that their payment has
# # failed and to retrieve new card details.
# messages.warning(request, 'Payment failed')
# logger.warning(data)
# if event_type == 'customer.subscription.deleted':
# # handle subscription canceled automatically based
# # upon your subscription settings. Or if the user cancels it.
# messages.error(request, 'Deleted')
# logger.warning(data)
subscription.create_order(event.data.object)
return JsonResponse({'status': 'success'})