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.
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/PKG-INFO +10 -5
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/README.md +9 -4
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/PKG-INFO +10 -5
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/cli.py +74 -13
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/tui.py +3 -2
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pyproject.toml +1 -1
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/LICENSE +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/SOURCES.txt +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/dependency_links.txt +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/entry_points.txt +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/requires.txt +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/basic_password_manager.egg-info/top_level.txt +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/__init__.py +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/crypto.py +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/logo.py +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/mobile.py +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/vault.py +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/web/argon2.umd.min.js +0 -0
- {basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/web/page.html +0 -0
- {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.
|
|
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`,
|
|
230
|
-
rather than the screen, so they don't sit in your terminal
|
|
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
|
-
-
|
|
302
|
-
|
|
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`,
|
|
214
|
-
rather than the screen, so they don't sit in your terminal
|
|
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
|
-
-
|
|
286
|
-
|
|
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.
|
|
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`,
|
|
230
|
-
rather than the screen, so they don't sit in your terminal
|
|
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
|
-
-
|
|
302
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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)",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{basic_password_manager-0.4.6 → basic_password_manager-0.4.7}/pw_manager/web/argon2.umd.min.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|