新增 Zalo OA、Zoom Chat、Zulip 三个渠道扩展。 Zalo OA 渠道扩展主要模块:sidecar_client, config, gateway, outbound, streaming, pairing, security, auth, dedupe, directory, monitor, status, session, reactions, tools Zoom Chat 渠道扩展主要模块:config, gateway, webhook, outbound, streaming, pairing, security, crypto, dedupe, actions, media, mentions, monitor, status, session, reactions, threading Zulip 渠道扩展主要模块:client, config, gateway, outbound, streaming, pairing, security, monitor, status
49 lines
1.4 KiB
Python
49 lines
1.4 KiB
Python
import hmac
|
|
import hashlib
|
|
import time
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
SIGNATURE_VERSION = "v0"
|
|
WEBHOOK_TOLERANCE_SECONDS = 300
|
|
|
|
|
|
def verify_webhook_signature(
|
|
raw_body: bytes,
|
|
signature_header: str,
|
|
timestamp_header: str,
|
|
webhook_secret: str,
|
|
tolerance_seconds: int = WEBHOOK_TOLERANCE_SECONDS,
|
|
) -> bool:
|
|
if not signature_header or not signature_header.startswith(f"{SIGNATURE_VERSION}="):
|
|
logger.warning("Webhook signature header missing or invalid prefix")
|
|
return False
|
|
|
|
expected_hex = signature_header[len(SIGNATURE_VERSION) + 1 :]
|
|
|
|
try:
|
|
request_ts = int(timestamp_header)
|
|
except (ValueError, TypeError):
|
|
logger.warning("Webhook timestamp header invalid: %s", timestamp_header)
|
|
return False
|
|
|
|
current_ts = int(time.time())
|
|
if abs(current_ts - request_ts) > tolerance_seconds:
|
|
logger.warning(
|
|
"Webhook timestamp out of tolerance: request=%s, current=%s, diff=%s",
|
|
request_ts,
|
|
current_ts,
|
|
abs(current_ts - request_ts),
|
|
)
|
|
return False
|
|
|
|
message = f"{timestamp_header}.{raw_body.decode('utf-8')}"
|
|
computed_hmac = hmac.new(
|
|
webhook_secret.encode("utf-8"),
|
|
message.encode("utf-8"),
|
|
hashlib.sha256,
|
|
).hexdigest()
|
|
|
|
return hmac.compare_digest(computed_hmac, expected_hex)
|