45 lines
1.1 KiB
Python
45 lines
1.1 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import hashlib
|
||
|
|
import hmac
|
||
|
|
import logging
|
||
|
|
import os
|
||
|
|
|
||
|
|
logger = logging.getLogger(__name__)
|
||
|
|
|
||
|
|
|
||
|
|
class HelpScoutWebhookHandler:
|
||
|
|
def __init__(self, queue):
|
||
|
|
self._queue = queue
|
||
|
|
|
||
|
|
async def handle(self, payload: dict) -> dict:
|
||
|
|
event_type = payload.pop("_event_type", "unknown")
|
||
|
|
logger.debug(
|
||
|
|
"Help Scout webhook received: type=%s conversation_id=%s",
|
||
|
|
event_type,
|
||
|
|
payload.get("conversation", {}).get("id", "N/A"),
|
||
|
|
)
|
||
|
|
|
||
|
|
if self._queue is not None:
|
||
|
|
await self._queue.put((event_type, payload))
|
||
|
|
|
||
|
|
return {"status": "ok"}
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def verify_signature(raw_body: bytes, signature: str) -> bool:
|
||
|
|
secret = os.getenv("HELPSCOUT_WEBHOOK_SECRET", "")
|
||
|
|
if not secret:
|
||
|
|
logger.warning("HELPSCOUT_WEBHOOK_SECRET not set — skipping signature verification")
|
||
|
|
return True
|
||
|
|
|
||
|
|
if not signature:
|
||
|
|
return False
|
||
|
|
|
||
|
|
expected = hmac.new(
|
||
|
|
secret.encode(),
|
||
|
|
raw_body,
|
||
|
|
hashlib.sha1,
|
||
|
|
).hexdigest()
|
||
|
|
|
||
|
|
return hmac.compare_digest(expected, signature)
|