from __future__ import annotations import logging import secrets import string from yuxi.channel.extensions.mattermost.security import normalize_allow_entry logger = logging.getLogger(__name__) PAIRING_CODE_LENGTH = 8 PAIRING_CODE_EXPIRY_SECONDS = 600 class MattermostPairingAdapter: def __init__(self): self._pending: dict[str, tuple[str, float]] = {} def generate_code(self, peer_id: str) -> str: import time as _time code = _generate_pairing_code() self._pending[peer_id] = (code, _time.time()) existing = [peer_id] for pid, (c, _) in list(self._pending.items()): if c == code: existing.append(pid) return code def verify_code(self, peer_id: str, code: str) -> bool: import time as _time if peer_id not in self._pending: return False stored_code, timestamp = self._pending[peer_id] now = _time.time() if now - timestamp > PAIRING_CODE_EXPIRY_SECONDS: self._pending.pop(peer_id, None) return False if stored_code != code.strip(): return False self._pending.pop(peer_id, None) return True def get_pending_code(self, peer_id: str) -> str | None: import time as _time if peer_id not in self._pending: return None code, timestamp = self._pending[peer_id] if _time.time() - timestamp > PAIRING_CODE_EXPIRY_SECONDS: self._pending.pop(peer_id, None) return None return code def clear_expired(self) -> None: import time as _time now = _time.time() expired = [ pid for pid, (_, ts) in self._pending.items() if now - ts > PAIRING_CODE_EXPIRY_SECONDS ] for pid in expired: self._pending.pop(pid, None) def is_paired(self, peer_id: str, allow_list: list[str]) -> bool: normalized = [normalize_allow_entry(e) for e in allow_list] return peer_id in normalized def _generate_pairing_code() -> str: chars = string.ascii_uppercase + string.digits raw = "".join(secrets.choice(chars) for _ in range(PAIRING_CODE_LENGTH)) return f"{raw[:4]}-{raw[4:]}"