import sys from pathlib import Path from tempfile import TemporaryDirectory from types import SimpleNamespace import pytest from helpers import create_vault, TEST_SEED, TEST_PASSWORD, dummy_nostr_client sys.path.append(str(Path(__file__).resolve().parents[1])) from seedpass.core.entry_management import EntryManager from seedpass.core.backup import BackupManager from seedpass.core.manager import PasswordManager, EncryptionMode from seedpass.core.config_manager import ConfigManager from constants import DEFAULT_PASSWORD_LENGTH class FakePasswordGenerator: def generate_password(self, length: int, index: int) -> str: # noqa: D401 return f"pw-{index}-{length}" def test_handle_add_password(monkeypatch, dummy_nostr_client, capsys): client, _relay = dummy_nostr_client 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) pm = PasswordManager.__new__(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.password_generator = FakePasswordGenerator() pm.parent_seed = TEST_SEED pm.nostr_client = client pm.fingerprint_dir = tmp_path pm.secret_mode_enabled = False pm.is_dirty = False inputs = iter( [ "Example", # label "", # username "", # url "", # notes "", # tags "n", # add custom field "", # length (default) "", # include special default "", # allowed special default "", # special mode default "", # exclude ambiguous default "", # min uppercase "", # min lowercase "", # min digits "", # min special ] ) monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) monkeypatch.setattr("seedpass.core.manager.pause", lambda *a, **k: None) monkeypatch.setattr(pm, "start_background_vault_sync", lambda *a, **k: None) pm.handle_add_password() out = capsys.readouterr().out entries = entry_mgr.list_entries(verbose=False) assert entries == [(0, "Example", "", "", False)] entry = entry_mgr.retrieve_entry(0) assert entry == { "label": "Example", "length": DEFAULT_PASSWORD_LENGTH, "username": "", "url": "", "archived": False, "type": "password", "kind": "password", "notes": "", "custom_fields": [], "tags": [], } assert f"pw-0-{DEFAULT_PASSWORD_LENGTH}" in out def test_handle_add_password_secret_mode(monkeypatch, dummy_nostr_client, capsys): client, _relay = dummy_nostr_client 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) pm = PasswordManager.__new__(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.password_generator = FakePasswordGenerator() pm.parent_seed = TEST_SEED pm.nostr_client = client pm.fingerprint_dir = tmp_path pm.secret_mode_enabled = True pm.clipboard_clear_delay = 5 pm.is_dirty = False inputs = iter( [ "Example", # label "", # username "", # url "", # notes "", # tags "n", # add custom field "", # length (default) "", # include special default "", # allowed special default "", # special mode default "", # exclude ambiguous default "", # min uppercase "", # min lowercase "", # min digits "", # min special ] ) monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) monkeypatch.setattr("seedpass.core.manager.pause", lambda *a, **k: None) monkeypatch.setattr(pm, "start_background_vault_sync", lambda *a, **k: None) called = [] monkeypatch.setattr( "seedpass.core.manager.copy_to_clipboard", lambda text, delay: called.append((text, delay)), ) pm.handle_add_password() out = capsys.readouterr().out assert f"pw-0-{DEFAULT_PASSWORD_LENGTH}" not in out assert "copied to clipboard" in out assert called == [(f"pw-0-{DEFAULT_PASSWORD_LENGTH}", 5)]