Example #1
0
    def validate(self, api_key=None):
        """
        The original contents of the Event message must be confirmed by
        refetching it and comparing the fetched data with the original data.

        This function makes an API call to Stripe to redownload the Event data
        and returns whether or not it matches the WebhookEventTrigger data.
        """

        local_data = self.json_body
        if "id" not in local_data or "livemode" not in local_data:
            return False

        if self.is_test_event:
            logger.info("Test webhook received: {}".format(local_data))
            return False

        if djstripe_settings.WEBHOOK_VALIDATION is None:
            # validation disabled
            return True
        elif (
            djstripe_settings.WEBHOOK_VALIDATION == "verify_signature"
            and djstripe_settings.WEBHOOK_SECRET
        ):
            # HTTP headers are case-insensitive, but we store them as a dict.
            headers = CaseInsensitiveMapping(self.headers)
            try:
                stripe.WebhookSignature.verify_header(
                    self.body,
                    headers.get("stripe-signature"),
                    djstripe_settings.WEBHOOK_SECRET,
                    djstripe_settings.WEBHOOK_TOLERANCE,
                )
            except stripe.error.SignatureVerificationError:
                return False
            else:
                return True

        livemode = local_data["livemode"]
        api_key = api_key or djstripe_settings.get_default_api_key(livemode)

        # Retrieve the event using the api_version specified in itself
        with stripe_temporary_api_version(local_data["api_version"], validate=False):
            remote_data = Event.stripe_class.retrieve(
                id=local_data["id"], api_key=api_key
            )

        return local_data["data"] == remote_data["data"]
Example #2
0
 def __init__(self, data):
     """
     Populate the initial data using __setitem__ to ensure values are
     correctly encoded.
     """
     if not isinstance(data, Mapping):
         data = {
             k: v
             for k, v in
             CaseInsensitiveMapping._destruct_iterable_mapping_values(data)
         }
     self._store = {}
     for header, value in data.items():
         self[header] = value
Example #3
0
 def test_str(self):
     dict1 = CaseInsensitiveMapping({'Accept': 'application/json'})
     dict2 = CaseInsensitiveMapping({'content-type': 'text/html'})
     self.assertEqual(str(dict1), str({'Accept': 'application/json'}))
     self.assertEqual(str(dict2), str({'content-type': 'text/html'}))
Example #4
0
 def test_create_with_invalid_key(self):
     msg = 'Element key 1 invalid, only strings are allowed'
     with self.assertRaisesMessage(ValueError, msg):
         CaseInsensitiveMapping([(1, '2')])
Example #5
0
 def test_create_with_invalid_values(self):
     msg = 'dictionary update sequence element #1 has length 4; 2 is required'
     with self.assertRaisesMessage(ValueError, msg):
         CaseInsensitiveMapping([('Key1', 'Val1'), 'Key2'])
Example #6
0
 def setUp(self):
     self.dict1 = CaseInsensitiveMapping({
         'Accept': 'application/json',
         'content-type': 'text/html',
     })
Example #7
0
class CaseInsensitiveMappingTests(SimpleTestCase):
    def setUp(self):
        self.dict1 = CaseInsensitiveMapping({
            'Accept': 'application/json',
            'content-type': 'text/html',
        })

    def test_create_with_invalid_values(self):
        msg = 'dictionary update sequence element #1 has length 4; 2 is required'
        with self.assertRaisesMessage(ValueError, msg):
            CaseInsensitiveMapping([('Key1', 'Val1'), 'Key2'])

    def test_create_with_invalid_key(self):
        msg = 'Element key 1 invalid, only strings are allowed'
        with self.assertRaisesMessage(ValueError, msg):
            CaseInsensitiveMapping([(1, '2')])

    def test_list(self):
        self.assertEqual(list(self.dict1), ['Accept', 'content-type'])

    def test_dict(self):
        self.assertEqual(dict(self.dict1), {'Accept': 'application/json', 'content-type': 'text/html'})

    def test_repr(self):
        dict1 = CaseInsensitiveMapping({'Accept': 'application/json'})
        dict2 = CaseInsensitiveMapping({'content-type': 'text/html'})
        self.assertEqual(repr(dict1), repr({'Accept': 'application/json'}))
        self.assertEqual(repr(dict2), repr({'content-type': 'text/html'}))

    def test_str(self):
        dict1 = CaseInsensitiveMapping({'Accept': 'application/json'})
        dict2 = CaseInsensitiveMapping({'content-type': 'text/html'})
        self.assertEqual(str(dict1), str({'Accept': 'application/json'}))
        self.assertEqual(str(dict2), str({'content-type': 'text/html'}))

    def test_equal(self):
        self.assertEqual(self.dict1, {'Accept': 'application/json', 'content-type': 'text/html'})
        self.assertNotEqual(self.dict1, {'accept': 'application/jso', 'Content-Type': 'text/html'})
        self.assertNotEqual(self.dict1, 'string')

    def test_items(self):
        other = {'Accept': 'application/json', 'content-type': 'text/html'}
        self.assertEqual(sorted(self.dict1.items()), sorted(other.items()))

    def test_copy(self):
        copy = self.dict1.copy()
        self.assertIs(copy, self.dict1)
        self.assertEqual(copy, self.dict1)

    def test_getitem(self):
        self.assertEqual(self.dict1['Accept'], 'application/json')
        self.assertEqual(self.dict1['accept'], 'application/json')
        self.assertEqual(self.dict1['aCCept'], 'application/json')
        self.assertEqual(self.dict1['content-type'], 'text/html')
        self.assertEqual(self.dict1['Content-Type'], 'text/html')
        self.assertEqual(self.dict1['Content-type'], 'text/html')

    def test_in(self):
        self.assertIn('Accept', self.dict1)
        self.assertIn('accept', self.dict1)
        self.assertIn('aCCept', self.dict1)
        self.assertIn('content-type', self.dict1)
        self.assertIn('Content-Type', self.dict1)

    def test_del(self):
        self.assertIn('Accept', self.dict1)
        msg = "'CaseInsensitiveMapping' object does not support item deletion"
        with self.assertRaisesMessage(TypeError, msg):
            del self.dict1['Accept']
        self.assertIn('Accept', self.dict1)

    def test_set(self):
        self.assertEqual(len(self.dict1), 2)
        msg = "'CaseInsensitiveMapping' object does not support item assignment"
        with self.assertRaisesMessage(TypeError, msg):
            self.dict1['New Key'] = 1
        self.assertEqual(len(self.dict1), 2)
 def test_str(self):
     dict1 = CaseInsensitiveMapping({"Accept": "application/json"})
     dict2 = CaseInsensitiveMapping({"content-type": "text/html"})
     self.assertEqual(str(dict1), str({"Accept": "application/json"}))
     self.assertEqual(str(dict2), str({"content-type": "text/html"}))
 def test_create_with_invalid_values(self):
     msg = "dictionary update sequence element #1 has length 4; 2 is required"
     with self.assertRaisesMessage(ValueError, msg):
         CaseInsensitiveMapping([("Key1", "Val1"), "Key2"])
 def setUp(self):
     self.dict1 = CaseInsensitiveMapping({
         "Accept": "application/json",
         "content-type": "text/html",
     })
class CaseInsensitiveMappingTests(SimpleTestCase):
    def setUp(self):
        self.dict1 = CaseInsensitiveMapping({
            "Accept": "application/json",
            "content-type": "text/html",
        })

    def test_create_with_invalid_values(self):
        msg = "dictionary update sequence element #1 has length 4; 2 is required"
        with self.assertRaisesMessage(ValueError, msg):
            CaseInsensitiveMapping([("Key1", "Val1"), "Key2"])

    def test_create_with_invalid_key(self):
        msg = "Element key 1 invalid, only strings are allowed"
        with self.assertRaisesMessage(ValueError, msg):
            CaseInsensitiveMapping([(1, "2")])

    def test_list(self):
        self.assertEqual(list(self.dict1), ["Accept", "content-type"])

    def test_dict(self):
        self.assertEqual(
            dict(self.dict1),
            {
                "Accept": "application/json",
                "content-type": "text/html"
            },
        )

    def test_repr(self):
        dict1 = CaseInsensitiveMapping({"Accept": "application/json"})
        dict2 = CaseInsensitiveMapping({"content-type": "text/html"})
        self.assertEqual(repr(dict1), repr({"Accept": "application/json"}))
        self.assertEqual(repr(dict2), repr({"content-type": "text/html"}))

    def test_str(self):
        dict1 = CaseInsensitiveMapping({"Accept": "application/json"})
        dict2 = CaseInsensitiveMapping({"content-type": "text/html"})
        self.assertEqual(str(dict1), str({"Accept": "application/json"}))
        self.assertEqual(str(dict2), str({"content-type": "text/html"}))

    def test_equal(self):
        self.assertEqual(self.dict1, {
            "Accept": "application/json",
            "content-type": "text/html"
        })
        self.assertNotEqual(self.dict1, {
            "accept": "application/jso",
            "Content-Type": "text/html"
        })
        self.assertNotEqual(self.dict1, "string")

    def test_items(self):
        other = {"Accept": "application/json", "content-type": "text/html"}
        self.assertEqual(sorted(self.dict1.items()), sorted(other.items()))

    def test_copy(self):
        copy = self.dict1.copy()
        self.assertIs(copy, self.dict1)
        self.assertEqual(copy, self.dict1)

    def test_getitem(self):
        self.assertEqual(self.dict1["Accept"], "application/json")
        self.assertEqual(self.dict1["accept"], "application/json")
        self.assertEqual(self.dict1["aCCept"], "application/json")
        self.assertEqual(self.dict1["content-type"], "text/html")
        self.assertEqual(self.dict1["Content-Type"], "text/html")
        self.assertEqual(self.dict1["Content-type"], "text/html")

    def test_in(self):
        self.assertIn("Accept", self.dict1)
        self.assertIn("accept", self.dict1)
        self.assertIn("aCCept", self.dict1)
        self.assertIn("content-type", self.dict1)
        self.assertIn("Content-Type", self.dict1)

    def test_del(self):
        self.assertIn("Accept", self.dict1)
        msg = "'CaseInsensitiveMapping' object does not support item deletion"
        with self.assertRaisesMessage(TypeError, msg):
            del self.dict1["Accept"]
        self.assertIn("Accept", self.dict1)

    def test_set(self):
        self.assertEqual(len(self.dict1), 2)
        msg = "'CaseInsensitiveMapping' object does not support item assignment"
        with self.assertRaisesMessage(TypeError, msg):
            self.dict1["New Key"] = 1
        self.assertEqual(len(self.dict1), 2)
Example #12
0
    def validate(
        self,
        api_key: str = None,
        secret: str = djstripe_settings.WEBHOOK_SECRET,
        tolerance: int = djstripe_settings.WEBHOOK_TOLERANCE,
        validation_method=djstripe_settings.WEBHOOK_VALIDATION,
    ):
        """
        The original contents of the Event message must be confirmed by
        refetching it and comparing the fetched data with the original data.

        This function makes an API call to Stripe to redownload the Event data
        and returns whether or not it matches the WebhookEventTrigger data.
        """

        local_data = self.json_body
        if "id" not in local_data or "livemode" not in local_data:
            logger.error(
                '"id" not in json body or "livemode" not in json body(%s)',
                local_data)
            return False

        if self.is_test_event:
            logger.info(
                "Test webhook received and discarded: {}".format(local_data))
            return False

        if validation_method is None:
            # validation disabled
            warnings.warn("WEBHOOK VALIDATION is disabled.")
            return True
        elif validation_method == "verify_signature":
            if not secret:
                raise ValueError(
                    "Cannot verify event signature without a secret")
            # HTTP headers are case-insensitive, but we store them as a dict.
            headers = CaseInsensitiveMapping(self.headers)
            signature = headers.get("stripe-signature")
            local_cli_signing_secret = headers.get("x-djstripe-webhook-secret")
            try:
                # check if the x-djstripe-webhook-secret Custom Header exists
                if local_cli_signing_secret:
                    # Set Endpoint Signing Secret to the output of Stripe CLI
                    # for signature verification
                    secret = local_cli_signing_secret

                stripe.WebhookSignature.verify_header(self.body, signature,
                                                      secret, tolerance)
            except stripe.error.SignatureVerificationError:
                logger.exception("Failed to verify header")
                return False
            else:
                return True

        livemode = local_data["livemode"]
        api_key = api_key or djstripe_settings.get_default_api_key(livemode)

        # Retrieve the event using the api_version specified in itself
        with stripe_temporary_api_version(local_data["api_version"],
                                          validate=False):
            remote_data = Event.stripe_class.retrieve(id=local_data["id"],
                                                      api_key=api_key)

        return local_data["data"] == remote_data["data"]