diora-web/tui/diora_tui/config.py

65 lines
1.8 KiB
Python
Raw Normal View History

"""The account the TUI syncs with: server, API token and the book key.
Token and key are stored protected (secretstore.py), the server and user name in the clear.
A config from before 2026-10 (token and key as plain JSON fields) is still read and is
rewritten protected at once.
"""
from __future__ import annotations
import json
import stat
from dataclasses import dataclass
from pathlib import Path
from . import paths, secretstore
_CONFIG_DIR = paths.config_dir()
_CONFIG_FILE = _CONFIG_DIR / "config.json"
@dataclass
class RemoteConfig:
server_url: str
api_token: str
enc_key_b64: str
username: str = ""
def load() -> RemoteConfig | None:
try:
data = json.loads(_CONFIG_FILE.read_text())
except (OSError, ValueError):
return None
if not isinstance(data, dict):
return None
try:
if "secret" in data:
secret = json.loads(secretstore.unprotect(data["secret"]))
return RemoteConfig(data["server_url"], secret["token"], secret["key"], data.get("username", ""))
cfg = RemoteConfig(data["server_url"], data["api_token"], data["enc_key_b64"], data.get("username", ""))
except (KeyError, ValueError, OSError):
return None
save(cfg) # a legacy plaintext config: protect it now
return cfg
def save(cfg: RemoteConfig) -> None:
_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
secret = json.dumps({"token": cfg.api_token, "key": cfg.enc_key_b64}).encode()
_CONFIG_FILE.write_text(json.dumps({
"server_url": cfg.server_url, "username": cfg.username, "secret": secretstore.protect(secret),
}, indent=2))
try:
_CONFIG_FILE.chmod(stat.S_IRUSR | stat.S_IWUSR)
except OSError:
pass
def forget() -> bool:
try:
_CONFIG_FILE.unlink()
return True
except OSError:
return False