ForcePilot/backend/package/yuxi/channel/extensions/aliyun_sms/pairing.py
Kris b8864ac12f feat(aliyun-sms): 新增阿里云短信渠道插件
实现完整的阿里云短信服务接入能力,包含短信发送、状态回执处理、上行消息接收、安全策略校验、会话管理等功能
2026-05-21 10:39:43 +08:00

73 lines
2.3 KiB
Python

from __future__ import annotations
import asyncio
import logging
import random
import time
from .format import mask_phone
logger = logging.getLogger(__name__)
PAIRING_CODE_LENGTH = 6
PAIRING_CODE_TTL = 600
PAIRING_CLEANUP_INTERVAL = 300
class AliyunSmsPairing:
def __init__(self):
self._codes: dict[str, dict] = {}
self._authorized: dict[str, set[str]] = {}
self._cleanup_task: asyncio.Task | None = None
async def generate_code(self, account_id: str) -> str:
code = str(random.randint(100000, 999999))
self._codes[code] = {
"account_id": account_id,
"expires_at": time.time() + PAIRING_CODE_TTL,
}
logger.info("阿里云短信配对码已生成: account=%s code=%s", account_id, code)
self._ensure_cleanup()
return code
async def verify_code(self, account_id: str, peer_id: str, code: str) -> bool:
entry = self._codes.get(code)
if not entry:
return False
if entry["account_id"] != account_id:
return False
if time.time() > entry["expires_at"]:
del self._codes[code]
return False
if account_id not in self._authorized:
self._authorized[account_id] = set()
self._authorized[account_id].add(peer_id)
del self._codes[code]
logger.info("阿里云短信配对验证成功: account=%s phone=%s", account_id, mask_phone(peer_id))
return True
def is_authorized(self, account_id: str, phone_number: str) -> bool:
return phone_number in self._authorized.get(account_id, set())
def revoke(self, account_id: str, phone_number: str):
if account_id in self._authorized:
self._authorized[account_id].discard(phone_number)
def _ensure_cleanup(self):
try:
loop = asyncio.get_running_loop()
if self._cleanup_task is None or self._cleanup_task.done():
self._cleanup_task = loop.create_task(self._cleanup_loop())
except RuntimeError:
pass
async def _cleanup_loop(self):
while True:
await asyncio.sleep(PAIRING_CLEANUP_INTERVAL)
now = time.time()
expired = [c for c, e in self._codes.items() if now > e["expires_at"]]
for code in expired:
del self._codes[code]