Add tests for ConfigManager

This commit is contained in:
thePR0M3TH3AN
2025-06-28 21:46:08 -04:00
parent d5e57593be
commit 5b7b18b8f4
3 changed files with 110 additions and 1 deletions

View File

@@ -5,9 +5,18 @@ import traceback
try:
from .manager import PasswordManager
logging.info("PasswordManager module imported successfully.")
except Exception as e:
logging.error(f"Failed to import PasswordManager module: {e}")
logging.error(traceback.format_exc()) # Log full traceback
__all__ = ['PasswordManager']
try:
from .config_manager import ConfigManager
logging.info("ConfigManager module imported successfully.")
except Exception as e:
logging.error(f"Failed to import ConfigManager module: {e}")
logging.error(traceback.format_exc())
__all__ = ["PasswordManager", "ConfigManager"]

View File

@@ -0,0 +1,71 @@
"""Config management for SeedPass profiles."""
from __future__ import annotations
import logging
from pathlib import Path
from typing import List
import bcrypt
from password_manager.encryption import EncryptionManager
from nostr.client import DEFAULT_RELAYS as DEFAULT_NOSTR_RELAYS
logger = logging.getLogger(__name__)
class ConfigManager:
"""Manage per-profile configuration encrypted on disk."""
CONFIG_FILENAME = "seedpass_config.json.enc"
def __init__(self, encryption_manager: EncryptionManager, fingerprint_dir: Path):
self.encryption_manager = encryption_manager
self.fingerprint_dir = fingerprint_dir
self.config_path = self.fingerprint_dir / self.CONFIG_FILENAME
def load_config(self) -> dict:
"""Load the configuration file, returning defaults if none exists."""
if not self.config_path.exists():
logger.info("Config file not found; returning defaults")
return {"relays": list(DEFAULT_NOSTR_RELAYS), "pin_hash": ""}
try:
data = self.encryption_manager.load_json_data(self.CONFIG_FILENAME)
if not isinstance(data, dict):
raise ValueError("Config data must be a dictionary")
# Ensure defaults for missing keys
data.setdefault("relays", list(DEFAULT_NOSTR_RELAYS))
data.setdefault("pin_hash", "")
return data
except Exception as exc:
logger.error(f"Failed to load config: {exc}")
raise
def save_config(self, config: dict) -> None:
"""Encrypt and save configuration."""
try:
self.encryption_manager.save_json_data(config, self.CONFIG_FILENAME)
except Exception as exc:
logger.error(f"Failed to save config: {exc}")
raise
def set_relays(self, relays: List[str]) -> None:
"""Update relay list and save."""
config = self.load_config()
config["relays"] = relays
self.save_config(config)
def set_pin(self, pin: str) -> None:
"""Hash and store the provided PIN."""
pin_hash = bcrypt.hashpw(pin.encode(), bcrypt.gensalt()).decode()
config = self.load_config()
config["pin_hash"] = pin_hash
self.save_config(config)
def verify_pin(self, pin: str) -> bool:
"""Check a provided PIN against the stored hash."""
config = self.load_config()
stored = config.get("pin_hash", "").encode()
if not stored:
return False
return bcrypt.checkpw(pin.encode(), stored)

View File

@@ -0,0 +1,29 @@
import bcrypt
from pathlib import Path
from tempfile import TemporaryDirectory
from cryptography.fernet import Fernet
import sys
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.config_manager import ConfigManager
from nostr.client import DEFAULT_RELAYS
def test_config_defaults_and_round_trip():
with TemporaryDirectory() as tmpdir:
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, Path(tmpdir))
cfg_mgr = ConfigManager(enc_mgr, Path(tmpdir))
cfg = cfg_mgr.load_config()
assert cfg["relays"] == list(DEFAULT_RELAYS)
assert cfg["pin_hash"] == ""
cfg_mgr.set_pin("1234")
cfg_mgr.set_relays(["wss://example.com"])
cfg2 = cfg_mgr.load_config()
assert cfg2["relays"] == ["wss://example.com"]
assert bcrypt.checkpw(b"1234", cfg2["pin_hash"].encode())