"""Multi-account support for Synology Chat channel. Manages multiple DSM connections with independent configurations, credential management, and default account routing. """ from __future__ import annotations from dataclasses import dataclass, field from typing import Any DEFAULT_ACCOUNT_ID = "default" _BASE_FIELD_KEYS = ( "dsm_url", "username", "password", "password_file", "verify_ssl", "name", ) @dataclass class AccountConfig: id: str dsm_url: str = "" username: str = "" password: str = "" password_file: str = "" verify_ssl: bool = True name: str = "" extra: dict[str, Any] = field(default_factory=dict) def list_account_ids(config: dict[str, Any]) -> list[str]: accounts = config.get("accounts", {}) if not isinstance(accounts, dict) or not accounts: return [DEFAULT_ACCOUNT_ID] return sorted(accounts.keys()) def resolve_account(config: dict[str, Any], account_id: str = DEFAULT_ACCOUNT_ID) -> AccountConfig: """Resolve configuration for a specific account with priority chain: account > base > env. For named accounts (non-default), base fields that are NOT explicitly overridden in the account config are cleared to prevent unwanted inheritance of sensitive values. """ base = { "dsm_url": config.get("dsm_url", ""), "username": config.get("username", ""), "password": config.get("password", ""), "password_file": config.get("password_file", ""), "verify_ssl": config.get("verify_ssl", True), "name": config.get("name", "synologychat"), } accounts = config.get("accounts", {}) account_cfg = accounts.get(account_id, {}) if isinstance(accounts, dict) else {} if account_id != DEFAULT_ACCOUNT_ID: merged = {} for k in _BASE_FIELD_KEYS: if k in account_cfg: merged[k] = account_cfg[k] else: merged[k] = "" if k not in ("verify_ssl", "name") else base[k] if "name" not in account_cfg: merged["name"] = merged["name"] or f"synologychat-{account_id}" else: merged = {k: account_cfg.get(k, base[k]) for k in base} return AccountConfig( id=account_id, dsm_url=merged["dsm_url"], username=merged["username"], password=merged["password"], password_file=merged["password_file"], verify_ssl=merged["verify_ssl"], name=merged["name"], extra={k: v for k, v in account_cfg.items() if k not in base}, ) def get_default_account_id(config: dict[str, Any]) -> str: return config.get("default_account", DEFAULT_ACCOUNT_ID) def has_multi_account(config: dict[str, Any]) -> bool: accounts = config.get("accounts", {}) return isinstance(accounts, dict) and len(accounts) > 0