from __future__ import annotations import hashlib from typing import Any DEFAULT_PROFILE_ID = "default" PROFILE_SESSION_TIMEOUT_SEC = 1800 def normalize_profile_id(value: Any) -> str: profile_id = str(value or "").strip() return profile_id if profile_id else DEFAULT_PROFILE_ID def _profile_key(value: Any) -> str: return normalize_profile_id(value).casefold() def normalize_pin(value: Any) -> str | None: pin = str(value or "").strip() if not pin: return None if not pin.isdigit(): return None if len(pin) < 4 or len(pin) > 6: return None return pin def hash_profile_pin(profile_id: str, pin: str) -> str: digest_input = f"{_profile_key(profile_id)}:{pin}" return hashlib.sha256(digest_input.encode("utf-8")).hexdigest() def first_query_param_value(query_params: Any, key: str) -> str | None: raw = query_params.get(key) if raw is None: return None if isinstance(raw, list): return str(raw[0]) if raw else None return str(raw) def is_truthy_flag(value: Any) -> bool: normalized = str(value or "").strip().lower() return normalized in {"1", "true", "yes", "y", "on"} def resolve_login_profile(session_profile: Any, query_profile: Any) -> str | None: if str(session_profile or "").strip(): return normalize_profile_id(session_profile) if str(query_profile or "").strip(): return normalize_profile_id(query_profile) return None def find_existing_profile_id(profile_id: Any, available_profiles: set[str]) -> str | None: requested_key = _profile_key(profile_id) for existing in available_profiles: if _profile_key(existing) == requested_key: return existing return None def profile_exists(profile_id: Any, available_profiles: set[str]) -> bool: return find_existing_profile_id(profile_id, available_profiles) is not None def is_profile_session_expired(last_active: Any, now_epoch: float, timeout_sec: int = PROFILE_SESSION_TIMEOUT_SEC) -> bool: if not isinstance(last_active, (int, float)): return False return (now_epoch - float(last_active)) > timeout_sec