新增京东(JD)渠道扩展,支持在 Yuxi 平台中集成京东客服渠道。 包含以下功能模块: - client: 京东 API 客户端封装 - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - webhook: Webhook 事件处理 - outbound: 外发消息管理 - pairing: 用户配对与绑定 - security: 安全校验 - signature: 请求签名验证 - crypto: 加解密处理 - dedupe: 消息去重 - monitor: 渠道状态监控 - status: 会话状态管理 - session: 会话管理 - business: 业务逻辑处理 - types: 类型定义
80 lines
2.1 KiB
Python
80 lines
2.1 KiB
Python
import base64
|
|
import hashlib
|
|
import hmac
|
|
import json
|
|
import time
|
|
from urllib.parse import quote
|
|
|
|
|
|
def sign_jos_request(params: dict, app_secret: str) -> str:
|
|
sorted_keys = sorted(params.keys())
|
|
|
|
sign_str = ""
|
|
for key in sorted_keys:
|
|
raw_value = str(params[key])
|
|
encoded = quote(raw_value, safe="")
|
|
sign_str += key + encoded
|
|
|
|
full_str = app_secret + sign_str + app_secret
|
|
signature = hmac.new(app_secret.encode("utf-8"), full_str.encode("utf-8"), hashlib.sha256).hexdigest().upper()
|
|
|
|
return signature
|
|
|
|
|
|
def build_signed_params(
|
|
method: str,
|
|
biz_params: dict,
|
|
app_key: str,
|
|
app_secret: str,
|
|
access_token: str,
|
|
) -> dict:
|
|
params = {
|
|
"method": method,
|
|
"app_key": app_key,
|
|
"access_token": access_token,
|
|
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
|
|
"format": "json",
|
|
"v": "2.0",
|
|
"sign_method": "hmac",
|
|
}
|
|
|
|
biz_json = json.dumps(biz_params, ensure_ascii=False, separators=(",", ":"))
|
|
params["360buy_param"] = biz_json
|
|
|
|
sign = sign_jos_request(params, app_secret)
|
|
params["sign"] = sign
|
|
|
|
return params
|
|
|
|
|
|
def verify_webhook_signature(
|
|
raw_body: bytes,
|
|
signature_header: str,
|
|
timestamp_header: str,
|
|
app_secret: str,
|
|
tolerance_seconds: int = 300,
|
|
algorithm: str = "hmac-sha256",
|
|
) -> bool:
|
|
try:
|
|
request_time = int(timestamp_header)
|
|
current_time = int(time.time())
|
|
if abs(current_time - request_time) > tolerance_seconds:
|
|
return False
|
|
except (ValueError, TypeError):
|
|
return False
|
|
|
|
if algorithm == "md5":
|
|
sign_str = app_secret + raw_body.decode("utf-8") + app_secret
|
|
expected = hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()
|
|
return signature_header.upper() == expected
|
|
|
|
sign_str = raw_body + timestamp_header.encode("utf-8")
|
|
computed = hmac.new(app_secret.encode("utf-8"), sign_str, hashlib.sha256).digest()
|
|
|
|
try:
|
|
expected = base64.b64decode(signature_header)
|
|
except Exception:
|
|
return False
|
|
|
|
return hmac.compare_digest(computed, expected)
|