From 2b6ce126b0c775675226ae6d2e291671c0cfad39 Mon Sep 17 00:00:00 2001 From: Joshua Nwachinemere <217677783+dk3yyyy@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:31:37 +0000 Subject: [PATCH] fix: accept full history confirmation responses --- README.md | 2 +- main.py | 9 +++------ tests/test_main.py | 10 ++++++---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 77699ab..3f0a30e 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ For random passwords, displayed entropy is `logâ‚‚` of the exact number of valid - Random choices use Python's `secrets` module. - Passphrases default to six independently selected EFF words (about 77.5 bits). - The web interface returns generated values only to the current page and does not write them to history. -- CLI history is written only when `--save-history` is supplied or the interactive save prompt is confirmed. +- CLI history is written only when `--save-history` is supplied or the interactive save prompt is confirmed with `Yes`, `yes`, `y`, or `Y`; `No`, `no`, `N`, `n`, and an empty response decline. - History and exports receive owner-only permissions on POSIX systems. - Custom wordlists are constrained to PassGen's local wordlist directory. diff --git a/main.py b/main.py index f895ca3..ccfeb33 100644 --- a/main.py +++ b/main.py @@ -667,12 +667,9 @@ def _run_once() -> bool: if args.copy: copy_flag = True if not save_history: - save_history = ( - console.input( - "[info]Save to local plaintext history? [y/N]: [/info]" - ).lower() - == "y" - ) + save_history = console.input( + "[info]Save to local plaintext history? [y/N]: [/info]" + ).strip().lower() in {"y", "yes"} else: passphrase_mode = args.passphrase length = args.length diff --git a/tests/test_main.py b/tests/test_main.py index 107a628..4aa9403 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -501,8 +501,9 @@ def test_interactive_export_with_no_history_returns_to_menu( assert "No passwords to export" in output assert "Goodbye" in output + @pytest.mark.parametrize("save_response", ["Yes", "yes", "y", "Y"]) def test_interactive_generation_can_opt_in_to_history( - self, monkeypatch, tmp_path + self, monkeypatch, tmp_path, save_response ): self.configure_paths(monkeypatch, tmp_path) monkeypatch.setattr(main_module, "password_history", main_module.PasswordHistory()) @@ -520,7 +521,7 @@ def test_interactive_generation_can_opt_in_to_history( "1", "wifi", "n", - "y", + save_response, "q", ] ) @@ -532,8 +533,9 @@ def test_interactive_generation_can_opt_in_to_history( assert len(stored) == 1 assert stored[0]["category"] == "wifi" + @pytest.mark.parametrize("save_response", ["No", "no", "N", "n"]) def test_interactive_generation_does_not_save_when_prompt_is_declined( - self, monkeypatch, tmp_path + self, monkeypatch, tmp_path, save_response ): self.configure_paths(monkeypatch, tmp_path) monkeypatch.setattr(main_module, "password_history", main_module.PasswordHistory()) @@ -551,7 +553,7 @@ def test_interactive_generation_does_not_save_when_prompt_is_declined( "1", "", "n", - "n", + save_response, "q", ] )