@@ -133,84 +133,66 @@ def verify_webhook(
133133 ).hexdigest ()
134134 return signature == x_signature
135135
136- def decompress_webhook_body (
136+ def verify_and_parse_webhook (
137137 self ,
138138 body : Union [bytes , str ],
139- content_encoding : Optional [str ] = None ,
140- payload_encoding : Optional [str ] = None ,
141- ) -> bytes :
142- """Decode a (possibly compressed and/or wrapped) webhook payload.
143-
144- Stream Chat can compress outbound webhook payloads with gzip and, for
145- SQS / SNS firehose delivery, also wrap the compressed bytes in base64
146- so they remain valid UTF-8 over the queue. This helper applies the
147- encodings in order:
148-
149- 1. ``payload_encoding`` (``"base64"`` / ``"b64"``) is unwrapped first.
150- 2. ``content_encoding`` (``"gzip"``) is decompressed next.
151- 3. The raw JSON bytes are returned. The caller can ``.decode("utf-8")``
152- or pass the value straight to :func:`json.loads`, which accepts
153- bytes.
154-
155- ``None`` or an empty string for either encoding is a no-op, so the
156- regular HTTP webhook path stays bytewise identical to today.
157-
158- This method does **not** check the ``X-Signature`` header. Use
159- :meth:`verify_and_decode_webhook` for the combined decode + verify
160- flow.
161-
162- :param body: raw bytes (or str) received from Stream
163- :param content_encoding: value of the ``Content-Encoding`` header
164- (only ``"gzip"`` is supported)
165- :param payload_encoding: wrapper around the compressed bytes
166- (``"base64"`` / ``"b64"``); used by the SQS / SNS firehose
167- :returns: the uncompressed JSON body as bytes
168- """
169- from stream_chat .webhook import decompress_webhook_body
170-
171- return decompress_webhook_body (
172- body ,
173- content_encoding = content_encoding ,
174- payload_encoding = payload_encoding ,
175- )
139+ signature : Union [str , bytes ],
140+ ) -> Dict [str , Any ]:
141+ """Verify and parse an HTTP webhook event.
142+
143+ Decompresses ``body`` when gzipped (detected from the body bytes),
144+ verifies the ``X-Signature`` header against the app's API secret,
145+ and returns the parsed event. The Python SDK currently returns a
146+ ``dict``; typed event classes are planned for a future release.
176147
177- def verify_and_decode_webhook (
148+ :param body: raw HTTP request body bytes Stream signed
149+ :param signature: ``X-Signature`` header value
150+ :raises stream_chat.base.exceptions.WebhookSignatureError: on
151+ signature mismatch or any decode error
152+ """
153+ from stream_chat .webhook import verify_and_parse_webhook
154+
155+ return verify_and_parse_webhook (body , signature , self .api_secret )
156+
157+ def verify_and_parse_sqs (
178158 self ,
179- body : Union [bytes , str ],
180- x_signature : Union [str , bytes ],
181- content_encoding : Optional [str ] = None ,
182- payload_encoding : Optional [str ] = None ,
183- ) -> bytes :
184- """Decode a webhook payload and verify its HMAC-SHA256 signature.
185-
186- The signature is always computed over the **uncompressed** JSON
187- payload, so this method first decodes the body via
188- :meth:`decompress_webhook_body` and then compares the digest with
189- ``x_signature`` using :func:`hmac.compare_digest`.
190-
191- Works for plain HTTP webhooks (pass the ``Content-Encoding`` header
192- value) and for SQS / SNS firehose envelopes (additionally pass
193- ``payload_encoding="base64"``).
194-
195- :param body: raw bytes (or str) received from Stream
196- :param x_signature: the ``X-Signature`` header value sent by Stream
197- :param content_encoding: value of the ``Content-Encoding`` header
198- (only ``"gzip"`` is supported)
199- :param payload_encoding: wrapper around the compressed bytes
200- (``"base64"`` / ``"b64"``); used by the SQS / SNS firehose
201- :returns: the verified, uncompressed JSON body as bytes
159+ message_body : Union [bytes , str ],
160+ signature : Union [str , bytes ],
161+ ) -> Dict [str , Any ]:
162+ """Verify and parse an SQS firehose webhook event.
163+
164+ Reverses the base64 (+ optional gzip) wrapping on the SQS
165+ ``Body``, verifies the ``X-Signature`` message attribute against
166+ the app's API secret, and returns the parsed event.
167+
168+ :param message_body: SQS message ``Body`` (string)
169+ :param signature: ``X-Signature`` message attribute value
202170 :raises stream_chat.base.exceptions.WebhookSignatureError: on
203171 signature mismatch or any decode error
204172 """
205- from stream_chat .webhook import verify_and_decode_webhook
173+ from stream_chat .webhook import verify_and_parse_sqs
206174
207- return verify_and_decode_webhook (
208- body ,
209- x_signature ,
210- api_secret = self .api_secret ,
211- content_encoding = content_encoding ,
212- payload_encoding = payload_encoding ,
213- )
175+ return verify_and_parse_sqs (message_body , signature , self .api_secret )
176+
177+ def verify_and_parse_sns (
178+ self ,
179+ message : Union [bytes , str ],
180+ signature : Union [str , bytes ],
181+ ) -> Dict [str , Any ]:
182+ """Verify and parse an SNS firehose webhook event.
183+
184+ Reverses the base64 (+ optional gzip) wrapping on the SNS
185+ ``Message``, verifies the ``X-Signature`` message attribute
186+ against the app's API secret, and returns the parsed event.
187+
188+ :param message: SNS notification ``Message`` field (string)
189+ :param signature: ``X-Signature`` message attribute value
190+ :raises stream_chat.base.exceptions.WebhookSignatureError: on
191+ signature mismatch or any decode error
192+ """
193+ from stream_chat .webhook import verify_and_parse_sns
194+
195+ return verify_and_parse_sns (message , signature , self .api_secret )
214196
215197 @abc .abstractmethod
216198 def update_app_settings (
0 commit comments