"""User manager — handles guest sessions, authentication, and profiles.""" import json import hashlib import secrets import logging from datetime import datetime, timedelta from typing import Optional from database.repositories import UserRepo, SettingsRepo from database import engine as db_engine logger = logging.getLogger("synapse.users") class UserManager: """Manages user accounts and sessions.""" def __init__(self): self._guest_sessions: dict[str, dict] = {} async def get_or_create_guest(self, session_id: str = None) -> dict: if not session_id: session_id = f"guest_{secrets.token_hex(8)}" if session_id in self._guest_sessions: return self._guest_sessions[session_id] user = await UserRepo.get_by_username(session_id) if not user: user = await UserRepo.create( username=session_id, display_name="Guest", ) self._guest_sessions[session_id] = user return user async def register(self, username: str, display_name: str = None, email: str = None, password: str = None) -> dict: existing = await UserRepo.get_by_username(username) if existing: raise ValueError("Username already exists") user = await UserRepo.create( username=username, display_name=display_name or username, email=email, ) if password: from database import engine pw_hash = hashlib.sha256(password.encode()).hexdigest() await SettingsRepo.set(user["id"], "password_hash", pw_hash) return user async def authenticate(self, username: str, password: str) -> Optional[dict]: user = await UserRepo.get_by_username(username) if not user: return None stored_hash = await SettingsRepo.get(user["id"], "password_hash") if not stored_hash: return None pw_hash = hashlib.sha256(password.encode()).hexdigest() if pw_hash != stored_hash: return None return user async def get_profile(self, user_id: str) -> Optional[dict]: return await UserRepo.get_by_id(user_id) async def update_profile(self, user_id: str, **kwargs) -> None: user = await UserRepo.get_by_id(user_id) if not user: return prefs = json.loads(user.get("preferences", "{}")) prefs.update(kwargs) await UserRepo.update_preferences(user_id, prefs) async def get_settings(self, user_id: str) -> dict: return await SettingsRepo.get_all(user_id) async def set_setting(self, user_id: str, key: str, value: str) -> None: await SettingsRepo.set(user_id, key, value) async def get_setting(self, user_id: str, key: str) -> Optional[str]: return await SettingsRepo.get(user_id, key) user_manager = UserManager()