"""Atlus configuration — paths, JWT settings, defaults.""" import os import json import secrets from pathlib import Path # --------------------------------------------------------------------------- # Paths # --------------------------------------------------------------------------- BASE_DIR = Path(__file__).resolve().parent.parent # repo root FRONTEND_DIR = BASE_DIR / "frontend" _default_config = "/etc/atlus" if os.path.exists("/etc") and os.access("/etc", os.W_OK) else str(BASE_DIR / ".atlus_data") _default_data = "/var/lib/atlus" if os.path.exists("/var/lib") and os.access("/var/lib", os.W_OK) else str(BASE_DIR / ".atlus_data") CONFIG_DIR = Path(os.environ.get("ATLUS_CONFIG_DIR", _default_config)) DATA_DIR = Path(os.environ.get("ATLUS_DATA_DIR", _default_data)) USER_CONFIG_FILE = CONFIG_DIR / "atlus.json" # --------------------------------------------------------------------------- # Server # --------------------------------------------------------------------------- HOST = os.environ.get("ATLUS_HOST", "0.0.0.0") PORT = int(os.environ.get("ATLUS_PORT", "7779")) # --------------------------------------------------------------------------- # JWT # --------------------------------------------------------------------------- JWT_SECRET_FILE = DATA_DIR / "jwt_secret" JWT_ALGORITHM = "HS256" JWT_EXPIRY_HOURS = int(os.environ.get("ATLUS_JWT_EXPIRY_HOURS", "24")) # Revoked tokens (in-memory set, cleared on restart) _revoked_tokens: set[str] = set() def get_jwt_secret() -> str: """Return persistent JWT secret, generating one on first run.""" if JWT_SECRET_FILE.exists(): return JWT_SECRET_FILE.read_text().strip() JWT_SECRET_FILE.parent.mkdir(parents=True, exist_ok=True) secret = secrets.token_hex(32) JWT_SECRET_FILE.write_text(secret) JWT_SECRET_FILE.chmod(0o600) return secret def revoke_token(jti: str) -> None: _revoked_tokens.add(jti) def is_token_revoked(jti: str) -> bool: return jti in _revoked_tokens # --------------------------------------------------------------------------- # User config helpers (persisted JSON) # --------------------------------------------------------------------------- _DEFAULT_CONFIG: dict = { "hostname_display": None, # override for panel display "timezone": None, # e.g. "America/New_York", None=system "ntp_enabled": True, "dock_apps": [ "terminal", "files", "services", "tasks", "network", "settings" ], "panel_services": [], # systemd unit names to show in panel "gui_apps": [], # GUI apps: [{id, name, command, icon, args, target_fps}] "asi_bridge": { "cifs_share": "//192.168.10.120/share", "mount_point": "/mnt/asiair", "cifs_user": "anonymous", "cifs_pass": "", }, "session_timeout_minutes": 1440, # 24 h "stats_interval_seconds": 2, "update_check_enabled": True, "update_check_interval": 60, # seconds between update checks } def load_config() -> dict: """Load user config from disk, merged over defaults.""" cfg = dict(_DEFAULT_CONFIG) if USER_CONFIG_FILE.exists(): try: with open(USER_CONFIG_FILE) as f: user = json.load(f) cfg.update(user) except (json.JSONDecodeError, OSError): pass return cfg def save_config(cfg: dict) -> None: """Persist user config to disk.""" CONFIG_DIR.mkdir(parents=True, exist_ok=True) with open(USER_CONFIG_FILE, "w") as f: json.dump(cfg, f, indent=2) # --------------------------------------------------------------------------- # Stats push interval # --------------------------------------------------------------------------- STATS_INTERVAL = float(os.environ.get( "ATLUS_STATS_INTERVAL", str(load_config().get("stats_interval_seconds", 2)), ))