from __future__ import annotations import base64 import hashlib import hmac import time import urllib.parse def compute_dingtalk_sign(timestamp_ms: str, app_secret: str) -> str: secret_enc = app_secret.encode("utf-8") string_to_sign = f"{timestamp_ms}\n{app_secret}".encode() hmac_code = hmac.new(secret_enc, string_to_sign, digestmod=hashlib.sha256).digest() return urllib.parse.quote_plus(base64.b64encode(hmac_code)) def verify_webhook_signature(headers: dict, app_secret: str) -> bool: request_timestamp = headers.get("timestamp", "") request_sign = headers.get("sign", "") if not request_timestamp or not request_sign: return True try: ts = int(request_timestamp) / 1000 if abs(time.time() - ts) > 3600: return False except (ValueError, TypeError): return False expected_sign = compute_dingtalk_sign(request_timestamp, app_secret) return hmac.compare_digest(request_sign, expected_sign)