diff --git a/src/main.py b/src/main.py index 527b5f3..8e470d7 100644 --- a/src/main.py +++ b/src/main.py @@ -23,6 +23,7 @@ import importlib from seedpass.core.manager import PasswordManager from nostr.client import NostrClient from seedpass.core.entry_types import EntryType +from seedpass.core.config_manager import ConfigManager from constants import INACTIVITY_TIMEOUT, initialize_app from utils.password_prompt import ( PasswordPromptError, @@ -767,8 +768,18 @@ def handle_toggle_secret_mode(pm: PasswordManager) -> None: """Toggle secret mode and adjust clipboard delay.""" cfg = pm.config_manager if cfg is None: - print(colored("Configuration manager unavailable.", "red")) - return + vault = getattr(pm, "vault", None) + fingerprint_dir = getattr(pm, "fingerprint_dir", None) + if vault is not None and fingerprint_dir is not None: + try: + cfg = pm.config_manager = ConfigManager(vault, fingerprint_dir) + except Exception as exc: + logging.error(f"Failed to initialize ConfigManager: {exc}") + print(colored("Configuration manager unavailable.", "red")) + return + else: + print(colored("Configuration manager unavailable.", "red")) + return try: enabled = cfg.get_secret_mode_enabled() delay = cfg.get_clipboard_clear_delay() diff --git a/src/seedpass/core/manager.py b/src/seedpass/core/manager.py index a90d19d..a153cd6 100644 --- a/src/seedpass/core/manager.py +++ b/src/seedpass/core/manager.py @@ -538,6 +538,10 @@ class PasswordManager: ) ) + # Ensure managers are initialized for the newly created profile + if getattr(self, "config_manager", None) is None: + self.initialize_managers() + except Exception as e: logger.error(f"Error adding new seed profile: {e}", exc_info=True) print(colored(f"Error: Failed to add new seed profile: {e}", "red")) @@ -960,6 +964,10 @@ class PasswordManager: print(colored("Invalid choice. Exiting.", "red")) sys.exit(1) + # Some seed loading paths may not initialize managers; ensure they exist + if getattr(self, "config_manager", None) is None: + self.initialize_managers() + def setup_existing_seed( self, method: Literal["paste", "words"] = "paste", diff --git a/src/tests/test_secret_mode_profile_creation.py b/src/tests/test_secret_mode_profile_creation.py new file mode 100644 index 0000000..cd3446c --- /dev/null +++ b/src/tests/test_secret_mode_profile_creation.py @@ -0,0 +1,59 @@ +from pathlib import Path +from tempfile import TemporaryDirectory +from types import SimpleNamespace + +import pytest + +from main import handle_toggle_secret_mode +from seedpass.core.manager import PasswordManager +from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from utils.fingerprint import generate_fingerprint + + +def test_add_new_fingerprint_initializes_managers(monkeypatch, tmp_path): + pm = PasswordManager.__new__(PasswordManager) + monkeypatch.setattr(Path, "home", lambda: tmp_path) + pm.initialize_fingerprint_manager() + called = {} + + def fake_setup_existing_seed(method="paste"): + pm.current_fingerprint = "fp1" + pm.fingerprint_manager.current_fingerprint = "fp1" + pm.fingerprint_dir = tmp_path / "fp1" + pm.fingerprint_dir.mkdir() + return "fp1" + + monkeypatch.setattr(pm, "setup_existing_seed", fake_setup_existing_seed) + monkeypatch.setattr( + pm, "initialize_managers", lambda: called.setdefault("init", True) + ) + monkeypatch.setattr("builtins.input", lambda *a: "1") + pm.config_manager = None + pm.add_new_fingerprint() + assert called.get("init") is True + + +def test_toggle_secret_mode_after_profile_creation(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + monkeypatch.setattr(Path, "home", lambda: tmp_path) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + pm = PasswordManager.__new__(PasswordManager) + pm.vault = vault + pm.encryption_manager = enc_mgr + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = generate_fingerprint(TEST_SEED) + pm.secret_mode_enabled = False + pm.clipboard_clear_delay = 45 + pm.config_manager = None + + inputs = iter(["y", "10"]) + monkeypatch.setattr("builtins.input", lambda *a: next(inputs)) + handle_toggle_secret_mode(pm) + + assert pm.secret_mode_enabled is True + assert pm.clipboard_clear_delay == 10 + assert pm.config_manager is not None + cfg = pm.config_manager.load_config(require_pin=False) + assert cfg["secret_mode_enabled"] is True + assert cfg["clipboard_clear_delay"] == 10