From 7dc5434bb0ee116cdd5921ccc94f990364eb1040 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 7 Jul 2025 21:12:44 -0400 Subject: [PATCH] Add managed account loading --- src/password_manager/manager.py | 50 +++++++++++++++++++++++++ src/tests/test_managed_account_entry.py | 46 +++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/src/password_manager/manager.py b/src/password_manager/manager.py index 358846b..bd79bb7 100644 --- a/src/password_manager/manager.py +++ b/src/password_manager/manager.py @@ -57,6 +57,7 @@ from utils.terminal_utils import ( pause, clear_and_print_fingerprint, ) +from utils.fingerprint import generate_fingerprint from constants import MIN_HEALTHY_RELAYS from constants import ( @@ -124,6 +125,7 @@ class PasswordManager: self.inactivity_timeout: float = INACTIVITY_TIMEOUT self.secret_mode_enabled: bool = False self.clipboard_clear_delay: int = 45 + self.profile_stack: list[tuple[str, Path, str]] = [] # Initialize the fingerprint manager first self.initialize_fingerprint_manager() @@ -459,6 +461,54 @@ class PasswordManager: print(colored(f"Error: Failed to switch seed profiles: {e}", "red")) return False # Return False to indicate failure + def load_managed_account(self, index: int) -> None: + """Load a managed account derived from the current seed profile.""" + if not self.entry_manager or not self.parent_seed: + raise ValueError("Manager not initialized") + + seed = self.entry_manager.get_managed_account_seed(index, self.parent_seed) + managed_fp = generate_fingerprint(seed) + account_dir = self.fingerprint_dir / "accounts" / managed_fp + account_dir.mkdir(parents=True, exist_ok=True) + + self.profile_stack.append( + (self.current_fingerprint, self.fingerprint_dir, self.parent_seed) + ) + + self.current_fingerprint = managed_fp + self.fingerprint_dir = account_dir + self.parent_seed = seed + + key = derive_index_key(seed) + self.encryption_manager = EncryptionManager(key, account_dir) + self.vault = Vault(self.encryption_manager, account_dir) + + self.initialize_bip85() + self.initialize_managers() + self.locked = False + self.update_activity() + self.sync_index_from_nostr_if_missing() + + def exit_managed_account(self) -> None: + """Return to the parent seed profile if one is on the stack.""" + if not self.profile_stack: + return + fp, path, seed = self.profile_stack.pop() + + self.current_fingerprint = fp + self.fingerprint_dir = path + self.parent_seed = seed + + key = derive_index_key(seed) + self.encryption_manager = EncryptionManager(key, path) + self.vault = Vault(self.encryption_manager, path) + + self.initialize_bip85() + self.initialize_managers() + self.locked = False + self.update_activity() + self.sync_index_from_nostr() + def handle_existing_seed(self) -> None: """ Handles the scenario where an existing parent seed file is found. diff --git a/src/tests/test_managed_account_entry.py b/src/tests/test_managed_account_entry.py index 88f40f0..65603e2 100644 --- a/src/tests/test_managed_account_entry.py +++ b/src/tests/test_managed_account_entry.py @@ -4,6 +4,8 @@ from tempfile import TemporaryDirectory from helpers import create_vault, TEST_SEED, TEST_PASSWORD from utils.fingerprint import generate_fingerprint +import password_manager.manager as manager_module +from password_manager.manager import EncryptionMode sys.path.append(str(Path(__file__).resolve().parents[1])) @@ -48,3 +50,47 @@ def test_add_and_get_managed_account_seed(): expected = derive_seed_phrase(bip85, idx, 12) assert phrase_a == expected assert generate_fingerprint(phrase_a) == fp + + +def test_load_and_exit_managed_account(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + idx = entry_mgr.add_managed_account("acct", TEST_SEED) + seed = entry_mgr.get_managed_account_seed(idx, TEST_SEED) + fp = generate_fingerprint(seed) + acct_dir = tmp_path / "accounts" / fp + + pm = manager_module.PasswordManager.__new__(manager_module.PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.config_manager = cfg_mgr + pm.parent_seed = TEST_SEED + pm.current_fingerprint = "rootfp" + pm.fingerprint_dir = tmp_path + pm.profile_stack = [] + monkeypatch.setattr(pm, "initialize_bip85", lambda: None) + monkeypatch.setattr(pm, "initialize_managers", lambda: None) + monkeypatch.setattr(pm, "sync_index_from_nostr_if_missing", lambda: None) + monkeypatch.setattr(pm, "sync_index_from_nostr", lambda: None) + monkeypatch.setattr(pm, "update_activity", lambda: None) + + pm.load_managed_account(idx) + + assert pm.current_fingerprint == fp + assert pm.fingerprint_dir == acct_dir + assert pm.profile_stack[-1][0] == "rootfp" + assert pm.profile_stack[-1][1] == tmp_path + + pm.exit_managed_account() + + assert pm.current_fingerprint == "rootfp" + assert pm.fingerprint_dir == tmp_path + assert pm.profile_stack == []