def test_event_customer_updated_positive(self): strip_secret = "stripe_secret" with self.settings(STRIPE_WEBHOOK_SECRET=strip_secret): self.assertEqual(self.existed_user.stripe_id, None) json_event = self.read_json_event('customer.updated') json_event['data']['object']['email'] = self.existed_user.email timestamp = int(time.time()) signed_payload = f"{timestamp}.{json.dumps(json_event)}" computed_signature = WebhookSignature._compute_signature( signed_payload, strip_secret) # when header = { 'HTTP_STRIPE_SIGNATURE': f't={timestamp},v1={computed_signature}' } response = self.client.post(reverse("stripe_webhook"), data=json_event, content_type='application/json', **header) # then self.assertEqual(response.status_code, 200) # subscription not prolonging, cause it assumes it has already done in `checkout.session.completed` event user = User.objects.get(id=self.existed_user.id) self.assertEqual(user.stripe_id, json_event['data']['object']['id']) self.assertEqual(user.membership_expires_at, self.existed_user.membership_expires_at)
def test_event_checkout_session_completed_negative_payment_not_found(self): # given strip_secret = "stripe_secret" with self.settings(STRIPE_WEBHOOK_SECRET=strip_secret): json_event = self.read_json_event('checkout.session.completed') json_event['data']['object'][ 'id'] = "some-payment-reference-not-existed" # not existed payment reference timestamp = int(time.time()) signed_payload = f"{timestamp}.{json.dumps(json_event)}" computed_signature = WebhookSignature._compute_signature( signed_payload, strip_secret) # when header = { 'HTTP_STRIPE_SIGNATURE': f't={timestamp},v1={computed_signature}' } response = self.client.post(reverse("stripe_webhook"), data=json_event, content_type='application/json', **header) # then self.assertEqual( response.status_code, 409) # conflict due to payment not found (let it try latter) # subscription expiration not prolongated user = User.objects.get(id=self.existed_user.id) self.assertEqual(user.membership_expires_at, self.existed_user.membership_expires_at)
def test_event_invoice_paid_with_billing_reason_subscription_create_positive( self): # links: # https://stripe.com/docs/webhooks/signatures # https://stripe.com/docs/api/events/object # given strip_secret = "stripe_secret" with self.settings(STRIPE_WEBHOOK_SECRET=strip_secret): json_event = self.read_json_event('invoice.paid') json_event['data']['object']['id'] = f'payment-id-{uuid.uuid4()}' json_event['data']['object'][ 'billing_reason'] = "subscription_create" timestamp = int(time.time()) signed_payload = f"{timestamp}.{json.dumps(json_event)}" computed_signature = WebhookSignature._compute_signature( signed_payload, strip_secret) # when header = { 'HTTP_STRIPE_SIGNATURE': f't={timestamp},v1={computed_signature}' } response = self.client.post(reverse("stripe_webhook"), data=json_event, content_type='application/json', **header) # then self.assertEqual(response.status_code, 200) # subscription not prolonging, cause it assumes it has already done in `checkout.session.completed` event user = User.objects.get(id=self.existed_user.id) self.assertEqual(user.membership_expires_at, self.existed_user.membership_expires_at)
def has_permission(self, request, view): secret = getattr(settings, "STRIPE_WEBHOOK_SECRET", None) request_header = request.META.get("HTTP_STRIPE_SIGNATURE") if not (secret and request_header): log.info("webhook_stripe_denied", reason="no_secret_or_header") return False try: WebhookSignature.verify_header(request.body.decode(), request_header, secret, 300) except SignatureVerificationError: log.info("webhook_stripe_denied", reason="invalid_signature") return False return True
def test_event_invoice_paid_negative_user_not_found(self): # given strip_secret = "stripe_secret" with self.settings(STRIPE_WEBHOOK_SECRET=strip_secret): strip_secret = "stripe_secret" with self.settings(STRIPE_WEBHOOK_SECRET=strip_secret): self.existed_user.stripe_id = f'stripe-id-{uuid.uuid4()}' self.existed_user.save() json_event = self.read_json_event('invoice.paid') json_event['data']['object']['id'] = f'payment-id-{uuid.uuid4()}' json_event['data']['object']['billing_reason'] = "subscription_cycle" json_event['data']['object']['customer'] = "not-existed-user" timestamp = int(time.time()) signed_payload = f"{timestamp}.{json.dumps(json_event)}" computed_signature = WebhookSignature._compute_signature(signed_payload, strip_secret) # when header = {'HTTP_STRIPE_SIGNATURE': f't={timestamp},v1={computed_signature}'} response = self.client.post(reverse("stripe_webhook"), data=json_event, content_type='application/json', **header) # then self.assertEqual(response.status_code, 409) # conflict due to payment not found (let it try latter) # subscription expiration not prolonged user = User.objects.get(id=self.existed_user.id) self.assertEqual(user.membership_expires_at, self.existed_user.membership_expires_at)
def test_event_invoice_paid_with_billing_reason_subscription_cycle_positive(self): # given strip_secret = "stripe_secret" with self.settings(STRIPE_WEBHOOK_SECRET=strip_secret): self.existed_user.stripe_id = f'stripe-id-{uuid.uuid4()}' self.existed_user.save() json_event = self.read_json_event('invoice.paid') json_event['data']['object']['id'] = f'payment-id-{uuid.uuid4()}' json_event['data']['object']['billing_reason'] = "subscription_cycle" json_event['data']['object']['customer'] = self.existed_user.stripe_id product = PRODUCTS['club3_recurrent_yearly'] json_event['data']['object']['lines']["data"][0]["plan"]["id"] = product['stripe_id'] timestamp = int(time.time()) signed_payload = f"{timestamp}.{json.dumps(json_event)}" computed_signature = WebhookSignature._compute_signature(signed_payload, strip_secret) # when header = {'HTTP_STRIPE_SIGNATURE': f't={timestamp},v1={computed_signature}'} response = self.client.post(reverse("stripe_webhook"), data=json_event, content_type='application/json', **header) # then # subscription prolonged self.assertEqual(response.status_code, 200) # subscription prolonged user = User.objects.get(id=self.existed_user.id) self.assertAlmostEquals(user.membership_expires_at, self.existed_user.membership_expires_at + product['data']['timedelta'], delta=timedelta(seconds=10))
def test_event_checkout_session_completed_positive(self): # links: # https://stripe.com/docs/webhooks/signatures # https://stripe.com/docs/api/events/object # given product = PRODUCTS["club1"] opened_payment: Payment = Payment.create(reference=f"random-reference-{uuid.uuid4()}", user=self.existed_user, product=product) strip_secret = "stripe_secret" with self.settings(STRIPE_WEBHOOK_SECRET=strip_secret): json_event = self.read_json_event('checkout.session.completed') json_event['data']['object']['id'] = opened_payment.reference timestamp = int(time.time()) signed_payload = f"{timestamp}.{json.dumps(json_event)}" computed_signature = WebhookSignature._compute_signature(signed_payload, strip_secret) # when header = {'HTTP_STRIPE_SIGNATURE': f't={timestamp},v1={computed_signature}'} response = self.client.post(reverse("stripe_webhook"), data=json_event, content_type='application/json', **header) # then self.assertEqual(response.status_code, 200) # subscription prolongated user = User.objects.get(id=self.existed_user.id) self.assertAlmostEquals(user.membership_expires_at, self.existed_user.membership_expires_at + product['data']['timedelta'], delta=timedelta(seconds=10))
def _stripe_event(payload_dict): timestamp = int(time.time()) payload = json.dumps(payload_dict) hmac = WebhookSignature._compute_signature( "%d.%s" % (timestamp, payload), app.config["STRIPE_ENDPOINT_SECRET"]) signature = f"t={timestamp},v1={hmac},v0={hmac}" return signature, payload
def _get_signature(self, payload): # # https://stripe.com/docs/webhooks/signatures#prepare-payload decoded_payload = \ payload.decode('utf-8') signed_payload = f'{self.timestamp}.{decoded_payload}' expected_signature = WebhookSignature._compute_signature( signed_payload, settings.STRIPE_ENDPOINT_SECRET) return expected_signature
def _get_signature_headers(self, payload): timestamp = int(time.time()) raw_payload = json.dumps(payload).replace(": ", ":") raw_payload = raw_payload.replace(", ", ",") signed_payload = "{timestamp:d}.{raw_payload}".format( timestamp=timestamp, raw_payload=raw_payload) signature = WebhookSignature._compute_signature( signed_payload, stripe_settings.WEBHOOK_ENDPOINT_SECRET) return { "HTTP_STRIPE_SIGNATURE": ("t={timestamp:d},v1={signature}" ",v0=not_important".format(timestamp=timestamp, signature=signature)) }
def test_unhandled_event_accepted(self): timestamp = time.time() payload = json.dumps({ "type": "some.unknown.event", "data": { "object": "MOCK" } }) signature = WebhookSignature._compute_signature( "%d.%s" % (timestamp, payload), "sec_123") header_value = "t=%d,v1=%s" % (timestamp, signature) response = self.client.post( "/stripe/webhook", payload, content_type="application/json", HTTP_STRIPE_SIGNATURE=header_value, ) self.assertEqual(response.status_code, 204)
def test_checkout_session_completed(self, handler): timestamp = time.time() payload = json.dumps({ "type": "checkout.session.completed", "data": { "object": "MOCK" } }) signature = WebhookSignature._compute_signature( "%d.%s" % (timestamp, payload), "sec_123") header_value = "t=%d,v1=%s" % (timestamp, signature) response = self.client.post( "/stripe/webhook", payload, content_type="application/json", HTTP_STRIPE_SIGNATURE=header_value, ) self.assertEqual(response.status_code, 204) handler.assert_called_with("MOCK")