From 4a3f2f0d12e7536504c08fa67a1ec044f7c94442 Mon Sep 17 00:00:00 2001 From: usermaneGermane Date: Fri, 6 Nov 2026 18:24:29 +0200 Subject: [PATCH] Keep a copied password after locking (0.6.0) Same change as Client-Windows 2.8.0: locking, by hand or idle, no longer clears the clipboard. The 30 s auto-clear keeps running and closing still clears at once. The README's stale "Version 0.3.0" and "Windows 2.4.0" lines are corrected, and its version table gains 2.7.0 (not ported yet) and 2.8.0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011ojnyVg7ccsR3pZ64s7aRH --- README.md | 8 +++- sourceFiles/gui.py | 6 +-- sourceFiles/tests/test_clipboard_lock.py | 58 ++++++++++++++++++++++++ sourceFiles/version.py | 2 +- 4 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 sourceFiles/tests/test_clipboard_lock.py diff --git a/README.md b/README.md index 263d6f1..693b4f8 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ encrypted file. There is no account and no service behind it: it works entirely offline, and if you want two PCs in step you run the sync server yourself, on your own hardware. -**Version 0.3.0 — early.** It installs from a `.deb` on Ubuntu 22.04 or +**Version 0.6.0 — early.** It installs from a `.deb` on Ubuntu 22.04 or newer, or runs from source. It has so far been tested in CI only, on a virtual display, not yet on a real desktop. @@ -19,7 +19,8 @@ virtual display, not yet on a real desktop. | [PassMan-Server-Linux](https://github.com/usermaneGermane/PassMan-Server-Linux) | the sync server for Linux, run by systemd | **Same vaults as on Windows.** The vault file, the sync protocol and the -features are those of PassMan for Windows 2.4.0, which this was ported from. +features match PassMan for Windows 2.8.0, except the 2.7.0 redesign, which is +not ported yet (see *What is different from Windows*). A vault moves between a Windows PC and a Linux PC unchanged, and both sync with either server. @@ -107,6 +108,7 @@ screen if you sync. - **Clipboard.** PassMan uses Tk's own clipboard, so nothing like `xclip` needs installing. It works on X11 and, through XWayland, on Wayland. On X11 what PassMan copied disappears when PassMan closes. As on Windows, + locking leaves a copied password pasteable, closing clears it at once, and copied passwords are cleared after 30 seconds — but a clipboard manager (GNOME or KDE clipboard history, CopyQ, …) may keep its own copy, which no application can reach. @@ -130,6 +132,8 @@ Where that README names a Windows version, read the Linux one beside it: | 2.4.0 | 0.3.0 | deleting archived entries after N days | | 2.5.0 | 0.4.0 | switching servers no longer removes entries silently | | 2.6.0 | 0.5.0 | a copy that is not installed says LAB in its title | +| 2.7.0 | not yet | the redesigned window | +| 2.8.0 | 0.6.0 | locking no longer clears a copied password | (0.2.0 added the `.deb` package, which has no Windows counterpart.) diff --git a/sourceFiles/gui.py b/sourceFiles/gui.py index 914e652..37f76ff 100644 --- a/sourceFiles/gui.py +++ b/sourceFiles/gui.py @@ -846,10 +846,8 @@ def lock_vault(self, auto=False): self._cancel_idle_timer() if self.master_password and self.current_user: self._save() - if self._clip_text is not None: - if self._clip_job: - self.root.after_cancel(self._clip_job) - self._clear_clipboard(self._clip_text, quiet=True) + # A copied password outlives the lock: the usual auto-clear timer + # keeps running, so it can still be pasted until that fires. self.vault = self.master_password = self.current_user = None self._history_open.clear() self.search_query = "" diff --git a/sourceFiles/tests/test_clipboard_lock.py b/sourceFiles/tests/test_clipboard_lock.py new file mode 100644 index 0000000..1a9b706 --- /dev/null +++ b/sourceFiles/tests/test_clipboard_lock.py @@ -0,0 +1,58 @@ +""" +Locking the vault leaves a copied password on the clipboard. + +The auto-clear timer started by the copy keeps running, so the password can +still be pasted after a lock until that timer fires. +""" + +import pytest + +gui = pytest.importorskip("gui", reason="needs tkinter (bundled with Python)") + + +class FakeRoot: + def __init__(self): + self.cancelled = [] + + def after_cancel(self, job): + self.cancelled.append(job) + + +class FakeApp: + """Just enough of PasswordManagerGUI for lock_vault to run.""" + + lock_vault = gui.PasswordManagerGUI.lock_vault + + def __init__(self): + self.root = FakeRoot() + self.master_password = None # nothing unlocked → no save + self.current_user = None + self.vault = {} + self._clip_text = "s3cret" + self._clip_job = "clear-job" + self.cleared = [] + self._history_open = set() + + def _cancel_idle_timer(self): + pass + + def show_login_screen(self): + pass + + def toast(self, message, kind="info"): + pass + + def _clear_clipboard(self, expected, quiet=False): + self.cleared.append(expected) + + +@pytest.mark.parametrize("auto", [False, True]) +def test_lock_keeps_the_copied_password_and_its_timer(auto): + app = FakeApp() + + app.lock_vault(auto=auto) + + assert app.cleared == [] + assert app.root.cancelled == [] + assert app._clip_job == "clear-job" + assert app._clip_text == "s3cret" diff --git a/sourceFiles/version.py b/sourceFiles/version.py index 7affa5b..e8e8c7c 100644 --- a/sourceFiles/version.py +++ b/sourceFiles/version.py @@ -6,7 +6,7 @@ format changes. """ -__version__ = "0.5.0" +__version__ = "0.6.0" #: Container version PassMan writes today (see crypto_utils.MAGIC). VAULT_FORMAT = "PMV2"