From d71a4912bd9db1a8f59f79d8d570ea1cd4c44a23 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:51:18 -0400 Subject: [PATCH] docs: clarify secret mode clipboard behavior --- README.md | 6 +-- src/seedpass/cli.py | 6 ++- src/seedpass/core/manager.py | 11 +++++- src/tests/test_manager_add_password.py | 52 ++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8e62cbb..84951ef 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ SeedPass now uses the `portalocker` library for cross-platform file locking. No - **Optional External Backup Location:** Configure a second directory where backups are automatically copied. - **Auto-Lock on Inactivity:** Vault locks after a configurable timeout for additional security. - **Quick Unlock:** Optionally skip the password prompt after verifying once. -- **Secret Mode:** Copy retrieved passwords directly to your clipboard and automatically clear it after a delay. +- **Secret Mode:** When enabled, newly generated and retrieved passwords are copied to your clipboard and automatically cleared after a delay. - **Tagging Support:** Organize entries with optional tags and find them quickly via search. - **Manual Vault Export/Import:** Create encrypted backups or restore them using the CLI or API. - **Parent Seed Backup:** Securely save an encrypted copy of the master seed. @@ -386,11 +386,11 @@ When choosing **Add Entry**, you can now select from: ### Using Secret Mode -When **Secret Mode** is enabled, SeedPass copies retrieved passwords directly to your clipboard instead of displaying them on screen. The clipboard clears automatically after the delay you choose. +When **Secret Mode** is enabled, SeedPass copies newly generated and retrieved passwords directly to your clipboard instead of displaying them on screen. The clipboard clears automatically after the delay you choose. 1. From the main menu open **Settings** and select **Toggle Secret Mode**. 2. Choose how many seconds to keep passwords on the clipboard. -3. Retrieve an entry and SeedPass will confirm the password was copied. +3. Generate or retrieve an entry and SeedPass will confirm the password was copied. ### Viewing Entry Details diff --git a/src/seedpass/cli.py b/src/seedpass/cli.py index 1a6c80a..dd3f1af 100644 --- a/src/seedpass/cli.py +++ b/src/seedpass/cli.py @@ -527,7 +527,11 @@ def config_set(ctx: typer.Context, key: str, value: str) -> None: @config_app.command("toggle-secret-mode") def config_toggle_secret_mode(ctx: typer.Context) -> None: - """Interactively enable or disable secret mode.""" + """Interactively enable or disable secret mode. + + When enabled, newly generated and retrieved passwords are copied to the + clipboard instead of printed to the screen. + """ service = _get_config_service(ctx) try: enabled = service.get_secret_mode_enabled() diff --git a/src/seedpass/core/manager.py b/src/seedpass/core/manager.py index e14d55b..ce30289 100644 --- a/src/seedpass/core/manager.py +++ b/src/seedpass/core/manager.py @@ -1356,7 +1356,16 @@ class PasswordManager: "green", ) ) - print(colored(f"Password for {website_name}: {password}\n", "yellow")) + if self.secret_mode_enabled: + copy_to_clipboard(password, self.clipboard_clear_delay) + print( + colored( + f"[+] Password copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) + ) + else: + print(colored(f"Password for {website_name}: {password}\n", "yellow")) # Automatically push the updated encrypted index to Nostr so the # latest changes are backed up remotely. diff --git a/src/tests/test_manager_add_password.py b/src/tests/test_manager_add_password.py index 641bc5d..3579f48 100644 --- a/src/tests/test_manager_add_password.py +++ b/src/tests/test_manager_add_password.py @@ -79,3 +79,55 @@ def test_handle_add_password(monkeypatch, dummy_nostr_client, capsys): } 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) + ] + ) + 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)]