新增 Facebook Messenger 渠道扩展,支持在 Yuxi 平台中集成 Messenger 即时通讯渠道。 包含以下功能模块: - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - webhook: Webhook 事件处理 - outbound: 外发消息管理 - streaming: 流式消息处理 - pairing: 用户配对与绑定 - security: 安全校验 - dedupe: 消息去重 - monitor: 渠道状态监控 - status: 会话状态管理 - actions: 动作处理 - template: 消息模板 - quick_reply: 快捷回复 - private_reply: 私密回复 - handover: 转人工切换 - persona: 人设管理 - profile: 主页配置 - user: 用户信息 - insights: 数据洞察 - notification: 通知推送 - media: 媒体资源处理 - types: 类型定义
74 lines
2.5 KiB
Python
74 lines
2.5 KiB
Python
import hashlib
|
|
import hmac
|
|
import json
|
|
import logging
|
|
|
|
from fastapi import APIRouter, Request, HTTPException, Query
|
|
from fastapi.responses import PlainTextResponse, JSONResponse
|
|
|
|
router = APIRouter(prefix="/api/channel/messenger", tags=["messenger"])
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@router.get("/webhook")
|
|
async def verify_webhook(
|
|
hub_mode: str = Query(None, alias="hub.mode"),
|
|
hub_challenge: str = Query(None, alias="hub.challenge"),
|
|
hub_verify_token: str = Query(None, alias="hub.verify_token"),
|
|
):
|
|
from yuxi.channel.extensions.messenger.config import MessengerConfigAdapter
|
|
|
|
adapter = MessengerConfigAdapter()
|
|
account = adapter._build_account("default", {})
|
|
|
|
verify_token = account.get("verify_token", "")
|
|
if not verify_token:
|
|
raise HTTPException(status_code=500, detail="verify_token not configured")
|
|
|
|
if hub_mode == "subscribe" and hub_verify_token == verify_token:
|
|
logger.info("messenger webhook verified successfully")
|
|
return PlainTextResponse(hub_challenge or "", status_code=200)
|
|
|
|
logger.warning("messenger webhook verification failed: token mismatch")
|
|
raise HTTPException(status_code=403, detail="Verification failed")
|
|
|
|
|
|
@router.post("/webhook")
|
|
async def receive_webhook(request: Request):
|
|
body = await request.body()
|
|
|
|
if not _verify_signature(request.headers, body):
|
|
logger.warning("messenger webhook signature verification failed")
|
|
raise HTTPException(status_code=403, detail="Invalid signature")
|
|
|
|
payload = json.loads(body)
|
|
logger.debug(f"messenger webhook received: entries={len(payload.get('entry', []))}")
|
|
|
|
from yuxi.channel.extensions.messenger.gateway import _get_webhook_queue
|
|
|
|
queue = _get_webhook_queue()
|
|
if queue is not None:
|
|
await queue.put(payload)
|
|
|
|
return JSONResponse({"status": "ok"})
|
|
|
|
|
|
def _verify_signature(headers, body: bytes) -> bool:
|
|
from yuxi.channel.extensions.messenger.config import MessengerConfigAdapter
|
|
|
|
adapter = MessengerConfigAdapter()
|
|
account = adapter._build_account("default", {})
|
|
app_secret = account.get("app_secret", "")
|
|
|
|
if not app_secret:
|
|
logger.warning("messenger app_secret not set, skipping signature verification")
|
|
return True
|
|
|
|
expected = headers.get("X-Hub-Signature-256", "")
|
|
if not expected.startswith("sha256="):
|
|
return False
|
|
|
|
actual = hmac.new(app_secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
|
return hmac.compare_digest(f"sha256={actual}", expected)
|