Example #1
0
    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)
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
    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
Example #5
0
    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)
Example #6
0
    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))
Example #7
0
    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))
Example #8
0
    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
Example #9
0
    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
Example #10
0
    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))
        }
Example #11
0
 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)
Example #12
0
 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")