ForcePilot/backend/package/yuxi/channel/extensions/matrix/pairing.py

59 lines
1.9 KiB
Python
Raw Normal View History

from __future__ import annotations
import logging
import secrets
import time
from collections import OrderedDict
logger = logging.getLogger(__name__)
id_label = "matrixUserId"
_pairing_codes: OrderedDict[str, tuple[str, float]] = OrderedDict()
_PAIRING_MAX_SIZE = 10000
_PAIRING_TTL_SECONDS = 600
async def generate_code(peer_id: str, config: dict = None, account_id: str = None) -> str:
alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
code = "".join(secrets.choice(alphabet) for _ in range(8))
_evict_expired()
_pairing_codes[peer_id] = (code, time.monotonic() + _PAIRING_TTL_SECONDS)
if len(_pairing_codes) > _PAIRING_MAX_SIZE:
_pairing_codes.popitem(last=False)
logger.info("Generated pairing code for peer %s", peer_id)
return code
async def verify_code(peer_id: str, code: str, config: dict = None, account_id: str = None) -> bool:
_evict_expired()
stored = _pairing_codes.get(peer_id)
if stored is None:
logger.info("Pairing verify failed: no code for peer %s", peer_id)
return False
stored_code, expires_at = stored
if time.monotonic() > expires_at:
del _pairing_codes[peer_id]
logger.info("Pairing verify failed: code expired for peer %s", peer_id)
return False
if code.upper() != stored_code:
logger.info("Pairing verify failed: code mismatch for peer %s", peer_id)
return False
del _pairing_codes[peer_id]
logger.info("Pairing verified for peer %s", peer_id)
return True
def _evict_expired() -> None:
now = time.monotonic()
expired = [k for k, (_, exp) in _pairing_codes.items() if now > exp]
for k in expired:
del _pairing_codes[k]
def normalize_allow_entry(entry: str) -> str:
return entry.strip().lower()
async def notify_approval(config: dict, peer_id: str, account_id: str | None = None) -> None:
logger.info("Matrix pairing approved for %s", peer_id)