import os.path from contextlib import contextmanager from typing import Any, Generator import keyring from injectable import injectable from pykeepass import PyKeePass, create_database @injectable(singleton=True) class Passwords: def __init__(self): from app.config import get_settings settings = get_settings() with open(settings.kp.secret, "r") as fh: keyring.set_password("karl", "kp", fh.read().splitlines()[0]) self._path = settings.kp.file @contextmanager def open(self, mode: str = "r") -> Generator[PyKeePass | Any, Any, None]: kp = PyKeePass(self._path, password=keyring.get_password("karl", "kp")) \ if os.path.exists(self._path) else create_database(self._path, password=keyring.get_password("karl", "kp")) yield kp if mode == "rw": kp.save() def get_values(self, keys: list[str]) -> dict[str, str]: output = {} for k in keys: key_parts = k.split(".") path = key_parts[:-1] if len(key_parts) > 2 else None entry_name = key_parts[-2] field_name = key_parts[-1] with self.open() as kp: kp_entry = kp.find_entries(path=path, first=True, title=entry_name) output[k] = self._get_field_value(kp_entry, field_name) return output @staticmethod def _get_field_value(kp_entry, field_name): if kp_entry is None: return None match field_name: case "username": return kp_entry.username case "password": return kp_entry.password case "url": return kp_entry.url case _: return kp_entry.get_custom_property(field_name)