import os.path from contextlib import contextmanager from typing import Any, Generator import keyring from injectable import injectable from pykeepass import PyKeePass, create_database class KeyRequest: def __init__(self, prompt: str): self.field_name = None self.entry_name = None self.path = None self._parse_prompt(prompt) def _parse_prompt(self, prompt: str): pass # k_parts = k.split("/") # field_name = None # match len(k_parts): # case 1: # field_name = 'password' # case 2: # field_name = k_parts[1] # k = k_parts[0] # case _: # output[k] = None # continue # key_parts = k.split(".") # path = key_parts[:-1] if len(key_parts) > 2 else None # entry_name = key_parts[-1] @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: request = KeyRequest(k) with self.open() as kp: kp_entry = kp.find_entries(path=request.path, first=True, title=request.entry_name) output[k] = self._get_field_value(kp_entry, request.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)