basic-password-manager 0.4.3__tar.gz → 0.4.5__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.3 → basic_password_manager-0.4.5}/PKG-INFO +5 -3
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/README.md +4 -2
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/basic_password_manager.egg-info/PKG-INFO +5 -3
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pw_manager/logo.py +11 -2
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pw_manager/mobile.py +4 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pw_manager/tui.py +49 -3
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pyproject.toml +1 -1
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/LICENSE +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/basic_password_manager.egg-info/SOURCES.txt +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/basic_password_manager.egg-info/dependency_links.txt +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/basic_password_manager.egg-info/entry_points.txt +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/basic_password_manager.egg-info/requires.txt +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/basic_password_manager.egg-info/top_level.txt +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pw_manager/__init__.py +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pw_manager/cli.py +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pw_manager/crypto.py +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pw_manager/vault.py +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pw_manager/web/argon2.umd.min.js +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/pw_manager/web/page.html +0 -0
- {basic_password_manager-0.4.3 → basic_password_manager-0.4.5}/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.5
|
|
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
|
|
@@ -74,8 +74,10 @@ changing the master password all live there, along with others.
|
|
|
74
74
|
|
|
75
75
|

|
|
76
76
|
|
|
77
|
-
And themes. `t` opens the theme picker
|
|
78
|
-
|
|
77
|
+
And themes. `t` opens the theme picker — your current one is marked and
|
|
78
|
+
preselected, and arrowing through them previews each live before you commit
|
|
79
|
+
(Enter keeps it, Esc puts back what you had). The bundled ones — muted-slate
|
|
80
|
+
(default), dawn, matrix — are lifted with love from
|
|
79
81
|
[tuxedo](https://github.com/webstonehq/tuxedo)'s palettes, and all of
|
|
80
82
|
Textual's built-ins are in there too. Your pick sticks across runs. Even the
|
|
81
83
|
knight on the unlock screen dresses to match your theme, try it ;)
|
|
@@ -58,8 +58,10 @@ changing the master password all live there, along with others.
|
|
|
58
58
|
|
|
59
59
|

|
|
60
60
|
|
|
61
|
-
And themes. `t` opens the theme picker
|
|
62
|
-
|
|
61
|
+
And themes. `t` opens the theme picker — your current one is marked and
|
|
62
|
+
preselected, and arrowing through them previews each live before you commit
|
|
63
|
+
(Enter keeps it, Esc puts back what you had). The bundled ones — muted-slate
|
|
64
|
+
(default), dawn, matrix — are lifted with love from
|
|
63
65
|
[tuxedo](https://github.com/webstonehq/tuxedo)'s palettes, and all of
|
|
64
66
|
Textual's built-ins are in there too. Your pick sticks across runs. Even the
|
|
65
67
|
knight on the unlock screen dresses to match your theme, try it ;)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: basic-password-manager
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.5
|
|
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
|
|
@@ -74,8 +74,10 @@ changing the master password all live there, along with others.
|
|
|
74
74
|
|
|
75
75
|

|
|
76
76
|
|
|
77
|
-
And themes. `t` opens the theme picker
|
|
78
|
-
|
|
77
|
+
And themes. `t` opens the theme picker — your current one is marked and
|
|
78
|
+
preselected, and arrowing through them previews each live before you commit
|
|
79
|
+
(Enter keeps it, Esc puts back what you had). The bundled ones — muted-slate
|
|
80
|
+
(default), dawn, matrix — are lifted with love from
|
|
79
81
|
[tuxedo](https://github.com/webstonehq/tuxedo)'s palettes, and all of
|
|
80
82
|
Textual's built-ins are in there too. Your pick sticks across runs. Even the
|
|
81
83
|
knight on the unlock screen dresses to match your theme, try it ;)
|
|
@@ -75,9 +75,18 @@ def _tinted(pixel, tint, accent):
|
|
|
75
75
|
return tuple(int(c * lum) for c in base)
|
|
76
76
|
|
|
77
77
|
|
|
78
|
-
def _hex_rgb(color: str) -> tuple:
|
|
78
|
+
def _hex_rgb(color: str | None) -> tuple | None:
|
|
79
|
+
"""Parse #rrggbb to (r,g,b). Returns None for anything that isn't hex —
|
|
80
|
+
ANSI themes use names like 'ansi_blue', and those just mean 'no tint'."""
|
|
81
|
+
if not color:
|
|
82
|
+
return None
|
|
79
83
|
color = color.lstrip("#")
|
|
80
|
-
|
|
84
|
+
if len(color) != 6:
|
|
85
|
+
return None
|
|
86
|
+
try:
|
|
87
|
+
return tuple(int(color[i : i + 2], 16) for i in (0, 2, 4))
|
|
88
|
+
except ValueError:
|
|
89
|
+
return None
|
|
81
90
|
|
|
82
91
|
|
|
83
92
|
def rich_text(tint: str | None = None, accent: str | None = None) -> Text:
|
|
@@ -130,6 +130,10 @@ def _theme_colors() -> dict:
|
|
|
130
130
|
registry = {t.name: t for t in TUXEDO_THEMES}
|
|
131
131
|
registry.update(BUILTIN_THEMES)
|
|
132
132
|
cs = registry[name].to_color_system().generate()
|
|
133
|
+
# ANSI themes resolve to names like 'ansi_blue', not hex — the browser
|
|
134
|
+
# can't use those and the knight can't tint from them, so fall back
|
|
135
|
+
if not str(cs.get("background", "")).startswith("#"):
|
|
136
|
+
return default
|
|
133
137
|
return {**default, **cs}
|
|
134
138
|
except (OSError, KeyError, ImportError):
|
|
135
139
|
return default
|
|
@@ -17,7 +17,8 @@ from textual.command import DiscoveryHit, Hit, Hits, Provider
|
|
|
17
17
|
from textual.containers import Vertical
|
|
18
18
|
from textual.screen import ModalScreen, Screen
|
|
19
19
|
from textual.theme import Theme
|
|
20
|
-
from textual.widgets import DataTable, Footer, Input, Label, Static
|
|
20
|
+
from textual.widgets import DataTable, Footer, Input, Label, OptionList, Static
|
|
21
|
+
from textual.widgets.option_list import Option
|
|
21
22
|
|
|
22
23
|
from . import logo, vault
|
|
23
24
|
from .cli import VAULT_PATH, generate, import_csv, to_clipboard
|
|
@@ -102,6 +103,8 @@ class UnlockScreen(Screen):
|
|
|
102
103
|
self.query_one("#master", Input).clear()
|
|
103
104
|
return
|
|
104
105
|
self.app.master = event.value
|
|
106
|
+
# stop repainting the (now-hidden) unlock knight on every theme change
|
|
107
|
+
self.app.theme_changed_signal.unsubscribe(self)
|
|
105
108
|
self.app.push_screen(MainScreen())
|
|
106
109
|
|
|
107
110
|
|
|
@@ -166,7 +169,8 @@ def _qr_text(url: str, primary: str) -> tuple[Text, int]:
|
|
|
166
169
|
must give the widget exactly that width: a wrapped QR is a dead QR."""
|
|
167
170
|
import qrcode
|
|
168
171
|
|
|
169
|
-
|
|
172
|
+
rgb = logo._hex_rgb(primary) or (0, 0, 0) # ansi themes → plain black QR
|
|
173
|
+
r, g, b = rgb
|
|
170
174
|
while (r + g + b) / 765 > 0.45:
|
|
171
175
|
r, g, b = int(r * 0.8), int(g * 0.8), int(b * 0.8)
|
|
172
176
|
dark, light = f"rgb({r},{g},{b})", "rgb(255,255,255)"
|
|
@@ -277,6 +281,45 @@ class PasswdModal(ModalScreen):
|
|
|
277
281
|
self.dismiss(new)
|
|
278
282
|
|
|
279
283
|
|
|
284
|
+
class ThemeModal(ModalScreen):
|
|
285
|
+
"""Theme picker: cursor starts on the current theme, moving it previews
|
|
286
|
+
the theme live, Enter keeps it, Esc reverts to what you had."""
|
|
287
|
+
|
|
288
|
+
BINDINGS = [Binding("escape", "cancel", "cancel")]
|
|
289
|
+
|
|
290
|
+
def __init__(self) -> None:
|
|
291
|
+
super().__init__()
|
|
292
|
+
self.original = None
|
|
293
|
+
|
|
294
|
+
def compose(self) -> ComposeResult:
|
|
295
|
+
with Vertical(classes="modal-box", id="theme-box"):
|
|
296
|
+
yield Label("theme", classes="modal-title")
|
|
297
|
+
yield OptionList(id="theme-list")
|
|
298
|
+
yield Static("↑↓ preview · enter keeps · esc cancels", classes="modal-hint")
|
|
299
|
+
|
|
300
|
+
def on_mount(self) -> None:
|
|
301
|
+
self.original = self.app.theme
|
|
302
|
+
names = sorted(self.app.available_themes)
|
|
303
|
+
option_list = self.query_one(OptionList)
|
|
304
|
+
for name in names:
|
|
305
|
+
label = f"{name} ✓" if name == self.original else name
|
|
306
|
+
option_list.add_option(Option(label, id=name))
|
|
307
|
+
option_list.highlighted = names.index(self.original) # start on current
|
|
308
|
+
|
|
309
|
+
def on_option_list_option_highlighted(self, event: OptionList.OptionHighlighted) -> None:
|
|
310
|
+
if event.option.id:
|
|
311
|
+
self.app.theme = event.option.id # live preview
|
|
312
|
+
|
|
313
|
+
def on_option_list_option_selected(self, event: OptionList.OptionSelected) -> None:
|
|
314
|
+
if event.option.id:
|
|
315
|
+
self.app.theme = event.option.id # commit (persists via theme signal)
|
|
316
|
+
self.dismiss()
|
|
317
|
+
|
|
318
|
+
def action_cancel(self) -> None:
|
|
319
|
+
self.app.theme = self.original # revert the preview
|
|
320
|
+
self.dismiss()
|
|
321
|
+
|
|
322
|
+
|
|
280
323
|
class ConfirmModal(ModalScreen):
|
|
281
324
|
"""y/n confirmation."""
|
|
282
325
|
|
|
@@ -308,7 +351,7 @@ class MainScreen(Screen):
|
|
|
308
351
|
Binding("e", "edit", "edit"),
|
|
309
352
|
Binding("d", "delete", "delete"),
|
|
310
353
|
Binding("slash", "search", "search"),
|
|
311
|
-
Binding("t", "
|
|
354
|
+
Binding("t", "theme", "theme"),
|
|
312
355
|
Binding("escape", "clear_search", show=False),
|
|
313
356
|
Binding("q", "quit", "quit"),
|
|
314
357
|
]
|
|
@@ -432,6 +475,9 @@ class MainScreen(Screen):
|
|
|
432
475
|
|
|
433
476
|
self.app.push_screen(ConfirmModal(f"delete '{name}'?"), done)
|
|
434
477
|
|
|
478
|
+
def action_theme(self) -> None:
|
|
479
|
+
self.app.push_screen(ThemeModal())
|
|
480
|
+
|
|
435
481
|
def action_search(self) -> None:
|
|
436
482
|
self.query_one("#search", Input).focus()
|
|
437
483
|
|
|
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.3 → basic_password_manager-0.4.5}/pw_manager/web/argon2.umd.min.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|