basic-password-manager 0.4.6__tar.gz → 0.4.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/PKG-INFO +10 -5
  2. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/README.md +9 -4
  3. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/PKG-INFO +10 -5
  4. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/cli.py +74 -13
  5. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/tui.py +3 -2
  6. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pyproject.toml +1 -1
  7. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/LICENSE +0 -0
  8. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/SOURCES.txt +0 -0
  9. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/dependency_links.txt +0 -0
  10. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/entry_points.txt +0 -0
  11. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/requires.txt +0 -0
  12. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/top_level.txt +0 -0
  13. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/__init__.py +0 -0
  14. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/crypto.py +0 -0
  15. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/logo.py +0 -0
  16. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/mobile.py +0 -0
  17. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/vault.py +0 -0
  18. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/web/argon2.umd.min.js +0 -0
  19. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/web/page.html +0 -0
  20. {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basic-password-manager
3
- Version: 0.4.6
3
+ Version: 0.4.7
4
4
  Summary: The Paladin — a local encrypted password manager that lives in your terminal
5
5
  License-Expression: MIT
6
6
  Project-URL: Repository, https://github.com/Daisentaur/password-manager
@@ -226,8 +226,11 @@ Both are thin skins over the two modules above. The TUI (built with
226
226
  [Textual](https://textual.textualize.io)) holds the decrypted entries in
227
227
  memory for the session; the CLI re-derives the key per command.
228
228
 
229
- Passwords go to the clipboard (`wl-copy`/`xclip`/`xsel`, whichever exists)
230
- rather than the screen, so they don't sit in your terminal scrollback. One
229
+ Passwords go to the clipboard (`wl-copy`/`xclip`/`xsel`/`pbcopy`/`clip`,
230
+ whichever exists) rather than the screen, so they don't sit in your terminal
231
+ scrollback — and they're wiped from it 45 seconds later by a detached helper
232
+ (the CLI exits immediately, so an in-process timer would never fire). If
233
+ you've copied something else in the meantime, yours is left alone. One
231
234
  deliberate asymmetry: CLI `find` does *not* search passwords, because a CLI
232
235
  argument lands in your shell history forever — the TUI search box does,
233
236
  because nothing you type there is logged anywhere.
@@ -298,8 +301,10 @@ accounts from 2013. `paladin rm <name>` the corpses, or prune the CSV first.
298
301
 
299
302
  I'd rather you know these than find them:
300
303
 
301
- - No clipboard auto-clear yet: a copied password stays on the clipboard
302
- until you copy over it. Copy something else when you're done.
304
+ - The 45-second clipboard window is still a window: anything watching your
305
+ clipboard in that time sees the password. Set
306
+ `PALADIN_CLIPBOARD_SECONDS` lower if that bothers you (or `0` to keep the
307
+ old forever-behaviour).
303
308
  - While a command runs, decrypted data briefly exists in process memory.
304
309
  Malware already on your machine could read it — true of every password
305
310
  manager ever made; the vault protects the file at rest, not a compromised
@@ -210,8 +210,11 @@ Both are thin skins over the two modules above. The TUI (built with
210
210
  [Textual](https://textual.textualize.io)) holds the decrypted entries in
211
211
  memory for the session; the CLI re-derives the key per command.
212
212
 
213
- Passwords go to the clipboard (`wl-copy`/`xclip`/`xsel`, whichever exists)
214
- rather than the screen, so they don't sit in your terminal scrollback. One
213
+ Passwords go to the clipboard (`wl-copy`/`xclip`/`xsel`/`pbcopy`/`clip`,
214
+ whichever exists) rather than the screen, so they don't sit in your terminal
215
+ scrollback — and they're wiped from it 45 seconds later by a detached helper
216
+ (the CLI exits immediately, so an in-process timer would never fire). If
217
+ you've copied something else in the meantime, yours is left alone. One
215
218
  deliberate asymmetry: CLI `find` does *not* search passwords, because a CLI
216
219
  argument lands in your shell history forever — the TUI search box does,
217
220
  because nothing you type there is logged anywhere.
@@ -282,8 +285,10 @@ accounts from 2013. `paladin rm <name>` the corpses, or prune the CSV first.
282
285
 
283
286
  I'd rather you know these than find them:
284
287
 
285
- - No clipboard auto-clear yet: a copied password stays on the clipboard
286
- until you copy over it. Copy something else when you're done.
288
+ - The 45-second clipboard window is still a window: anything watching your
289
+ clipboard in that time sees the password. Set
290
+ `PALADIN_CLIPBOARD_SECONDS` lower if that bothers you (or `0` to keep the
291
+ old forever-behaviour).
287
292
  - While a command runs, decrypted data briefly exists in process memory.
288
293
  Malware already on your machine could read it — true of every password
289
294
  manager ever made; the vault protects the file at rest, not a compromised
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basic-password-manager
3
- Version: 0.4.6
3
+ Version: 0.4.7
4
4
  Summary: The Paladin — a local encrypted password manager that lives in your terminal
5
5
  License-Expression: MIT
6
6
  Project-URL: Repository, https://github.com/Daisentaur/password-manager
@@ -226,8 +226,11 @@ Both are thin skins over the two modules above. The TUI (built with
226
226
  [Textual](https://textual.textualize.io)) holds the decrypted entries in
227
227
  memory for the session; the CLI re-derives the key per command.
228
228
 
229
- Passwords go to the clipboard (`wl-copy`/`xclip`/`xsel`, whichever exists)
230
- rather than the screen, so they don't sit in your terminal scrollback. One
229
+ Passwords go to the clipboard (`wl-copy`/`xclip`/`xsel`/`pbcopy`/`clip`,
230
+ whichever exists) rather than the screen, so they don't sit in your terminal
231
+ scrollback — and they're wiped from it 45 seconds later by a detached helper
232
+ (the CLI exits immediately, so an in-process timer would never fire). If
233
+ you've copied something else in the meantime, yours is left alone. One
231
234
  deliberate asymmetry: CLI `find` does *not* search passwords, because a CLI
232
235
  argument lands in your shell history forever — the TUI search box does,
233
236
  because nothing you type there is logged anywhere.
@@ -298,8 +301,10 @@ accounts from 2013. `paladin rm <name>` the corpses, or prune the CSV first.
298
301
 
299
302
  I'd rather you know these than find them:
300
303
 
301
- - No clipboard auto-clear yet: a copied password stays on the clipboard
302
- until you copy over it. Copy something else when you're done.
304
+ - The 45-second clipboard window is still a window: anything watching your
305
+ clipboard in that time sees the password. Set
306
+ `PALADIN_CLIPBOARD_SECONDS` lower if that bothers you (or `0` to keep the
307
+ old forever-behaviour).
303
308
  - While a command runs, decrypted data briefly exists in process memory.
304
309
  Malware already on your machine could read it — true of every password
305
310
  manager ever made; the vault protects the file at rest, not a compromised
@@ -23,23 +23,84 @@ def generate(length: int = 20) -> str:
23
23
  return "".join(secrets.choice(alphabet) for _ in range(length))
24
24
 
25
25
 
26
- def to_clipboard(text: str) -> bool:
27
- # ponytail: no auto-clear timer; clear manually or copy something else over it
28
- # linux needs a tool installed; macOS (pbcopy) and Windows (clip) ship theirs
29
- for cmd in (
30
- ["wl-copy"],
31
- ["xclip", "-selection", "clipboard"],
32
- ["xsel", "-b"],
33
- ["pbcopy"],
34
- ["clip"],
35
- ["clip.exe"], # windows tool as seen from inside WSL
36
- ):
26
+ # seconds a copied password lingers before it's wiped; 0 disables
27
+ CLIPBOARD_TTL = int(os.environ.get("PALADIN_CLIPBOARD_SECONDS", "45"))
28
+
29
+ # linux needs a tool installed; macOS (pbcopy) and Windows (clip) ship theirs
30
+ _COPY_CMDS = (
31
+ ["wl-copy"],
32
+ ["xclip", "-selection", "clipboard"],
33
+ ["xsel", "-b"],
34
+ ["pbcopy"],
35
+ ["clip"],
36
+ ["clip.exe"], # windows tool as seen from inside WSL
37
+ )
38
+ _PASTE_CMDS = (
39
+ ["wl-paste", "-n"],
40
+ ["xclip", "-selection", "clipboard", "-o"],
41
+ ["xsel", "-b"],
42
+ ["pbpaste"],
43
+ ["powershell.exe", "-noprofile", "-command", "Get-Clipboard"],
44
+ )
45
+
46
+
47
+ def to_clipboard(text: str, auto_clear: bool = True) -> bool:
48
+ for cmd in _COPY_CMDS:
37
49
  if shutil.which(cmd[0]):
38
50
  subprocess.run(cmd, input=text.encode(), check=True)
51
+ if auto_clear and text and CLIPBOARD_TTL > 0:
52
+ _clear_clipboard_later(text)
39
53
  return True
40
54
  return False
41
55
 
42
56
 
57
+ def from_clipboard() -> str | None:
58
+ """Current clipboard contents, or None if we can't read it."""
59
+ for cmd in _PASTE_CMDS:
60
+ if shutil.which(cmd[0]):
61
+ try:
62
+ out = subprocess.run(cmd, capture_output=True, check=True).stdout
63
+ except subprocess.CalledProcessError:
64
+ return None
65
+ return out.decode(errors="replace").rstrip("\r\n")
66
+ return None
67
+
68
+
69
+ def _clear_clipboard_later(text: str) -> None:
70
+ """Hand the password to a detached child that wipes it later — the CLI
71
+ exits immediately after copying, so an in-process timer would never fire."""
72
+ try:
73
+ proc = subprocess.Popen(
74
+ [sys.executable, "-c", "from pw_manager.cli import _clear_worker; _clear_worker()"],
75
+ stdin=subprocess.PIPE,
76
+ stdout=subprocess.DEVNULL,
77
+ stderr=subprocess.DEVNULL,
78
+ start_new_session=True,
79
+ )
80
+ proc.stdin.write(text.encode()) # via stdin, never argv (argv shows in `ps`)
81
+ proc.stdin.close()
82
+ except OSError:
83
+ pass # clipboard hygiene is best-effort; never break the copy itself
84
+
85
+
86
+ def _clear_worker() -> None:
87
+ """Child: wait out the TTL, then clear the clipboard only if it still holds
88
+ the password we put there — never clobber something the user copied since."""
89
+ import time
90
+
91
+ copied = sys.stdin.buffer.read().decode()
92
+ time.sleep(CLIPBOARD_TTL)
93
+ current = from_clipboard()
94
+ if current is None or current == copied:
95
+ to_clipboard("", auto_clear=False) # no recursion
96
+
97
+
98
+ def copied_msg() -> str:
99
+ if CLIPBOARD_TTL > 0:
100
+ return f"password copied to clipboard (clears in {CLIPBOARD_TTL}s)"
101
+ return "password copied to clipboard"
102
+
103
+
43
104
  def ask_master(confirm: bool = False) -> str:
44
105
  pw = getpass.getpass("master password: ")
45
106
  if confirm:
@@ -122,7 +183,7 @@ def cmd_add(args):
122
183
  vault.save(VAULT_PATH, master, entries)
123
184
  print(f"stored '{args.name}'")
124
185
  if args.gen and to_clipboard(pw):
125
- print("password copied to clipboard")
186
+ print(copied_msg())
126
187
 
127
188
 
128
189
  def cmd_get(args):
@@ -134,7 +195,7 @@ def cmd_get(args):
134
195
  if e.get("notes"):
135
196
  print(f"notes: {e['notes']}")
136
197
  if to_clipboard(e["pw"]):
137
- print("password copied to clipboard")
198
+ print(copied_msg())
138
199
  else:
139
200
  # no clipboard tool found; showing it is the only option left
140
201
  print(f"password: {e['pw']}")
@@ -21,7 +21,7 @@ from textual.widgets import DataTable, Footer, Input, Label, OptionList, Static
21
21
  from textual.widgets.option_list import Option
22
22
 
23
23
  from . import logo, vault
24
- from .cli import VAULT_PATH, generate, import_csv, to_clipboard
24
+ from .cli import CLIPBOARD_TTL, VAULT_PATH, generate, import_csv, to_clipboard
25
25
 
26
26
  THEME_FILE = os.path.expanduser("~/.local/share/pw-manager/theme")
27
27
 
@@ -422,7 +422,8 @@ class MainScreen(Screen):
422
422
  if name is None:
423
423
  return
424
424
  if to_clipboard(self.app.entries[name]["pw"]):
425
- self.notify(f"password for '{name}' copied", severity="information")
425
+ ttl = f" (clears in {CLIPBOARD_TTL}s)" if CLIPBOARD_TTL > 0 else ""
426
+ self.notify(f"password for '{name}' copied{ttl}", severity="information")
426
427
  else:
427
428
  self.notify(
428
429
  "no clipboard tool found (on Linux: install wl-clipboard)",
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "basic-password-manager"
7
- version = "0.4.6"
7
+ version = "0.4.7"
8
8
  description = "The Paladin — a local encrypted password manager that lives in your terminal"
9
9
  readme = "README.md"
10
10
  license = "MIT"