mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-08 07:18:47 +00:00
Add tests for ConfigManager
This commit is contained in:
@@ -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"]
|
||||
|
71
src/password_manager/config_manager.py
Normal file
71
src/password_manager/config_manager.py
Normal 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)
|
29
src/tests/test_config_manager.py
Normal file
29
src/tests/test_config_manager.py
Normal 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())
|
Reference in New Issue
Block a user