Merge pull request #288 from PR0M3TH3AN/beta

Beta
This commit is contained in:
thePR0M3TH3AN
2025-07-05 14:38:33 -04:00
committed by GitHub
7 changed files with 245 additions and 23 deletions

View File

@@ -18,9 +18,9 @@ import hashlib
from typing import Optional
import shutil
import time
import select
import builtins
from termcolor import colored
from utils.input_utils import timed_input
from password_manager.encryption import EncryptionManager
from password_manager.entry_management import EntryManager
@@ -1285,14 +1285,12 @@ class PasswordManager:
sys.stdout.write(f"\r{bar} {remaining:2d}s")
sys.stdout.flush()
try:
if (
sys.stdin
in select.select([sys.stdin], [], [], 1)[0]
):
user_input = sys.stdin.readline().strip().lower()
if user_input == "b":
exit_loop = True
break
user_input = timed_input("", 1)
if user_input.strip().lower() == "b":
exit_loop = True
break
except TimeoutError:
pass
except KeyboardInterrupt:
exit_loop = True
print()
@@ -2009,10 +2007,11 @@ class PasswordManager:
print(f"[{idx}] {label}: {code} {bar} {remaining:2d}s")
sys.stdout.flush()
try:
if sys.stdin in select.select([sys.stdin], [], [], 1)[0]:
user_input = sys.stdin.readline().strip().lower()
if user_input == "b":
break
user_input = timed_input("", 1)
if user_input.strip().lower() == "b":
break
except TimeoutError:
pass
except KeyboardInterrupt:
print()
break

View File

@@ -30,6 +30,15 @@ from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.hazmat.backends import default_backend
from bip_utils import Bip39SeedGenerator
# Ensure the ``imghdr`` module is available for ``pgpy`` on Python 3.13+
try: # pragma: no cover - only executed on Python >= 3.13
import imghdr # type: ignore
except ModuleNotFoundError: # pragma: no cover - fallback for removed module
from utils import imghdr_stub as imghdr # type: ignore
import sys
sys.modules.setdefault("imghdr", imghdr)
from local_bip85.bip85 import BIP85
from constants import DEFAULT_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH

View File

@@ -50,7 +50,7 @@ def test_handle_display_totp_codes(monkeypatch, capsys):
# interrupt the loop after first iteration
monkeypatch.setattr(
"password_manager.manager.select.select",
"password_manager.manager.timed_input",
lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()),
)
@@ -91,7 +91,7 @@ def test_display_totp_codes_excludes_blacklisted(monkeypatch, capsys):
)
monkeypatch.setattr(
"password_manager.manager.select.select",
"password_manager.manager.timed_input",
lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()),
)

View File

@@ -69,10 +69,9 @@ def test_list_entries_show_details(monkeypatch, capsys):
pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 1
)
monkeypatch.setattr("password_manager.manager.time.sleep", lambda *a, **k: None)
monkeypatch.setattr(sys.stdin, "readline", lambda *a, **k: "b\n")
monkeypatch.setattr(
"password_manager.manager.select.select",
lambda *a, **k: ([sys.stdin], [], []),
"password_manager.manager.timed_input",
lambda *a, **k: "b",
)
inputs = iter(["1", "0"])

View File

@@ -49,10 +49,9 @@ def test_handle_retrieve_totp_entry(monkeypatch, capsys):
pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 1
)
monkeypatch.setattr("password_manager.manager.time.sleep", lambda *a, **k: None)
monkeypatch.setattr(sys.stdin, "readline", lambda *a, **k: "b\n")
monkeypatch.setattr(
"password_manager.manager.select.select",
lambda *a, **k: ([sys.stdin], [], []),
"password_manager.manager.timed_input",
lambda *a, **k: "b",
)
pm.handle_retrieve_entry()

View File

@@ -66,7 +66,7 @@ def test_totp_display_secret_mode(monkeypatch, capsys):
pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30
)
monkeypatch.setattr(
"password_manager.manager.select.select",
"password_manager.manager.timed_input",
lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()),
)
called = []
@@ -115,7 +115,7 @@ def test_totp_display_no_secret_mode(monkeypatch, capsys):
pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30
)
monkeypatch.setattr(
"password_manager.manager.select.select",
"password_manager.manager.timed_input",
lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()),
)
called = []

216
src/utils/imghdr_stub.py Normal file
View File

@@ -0,0 +1,216 @@
"""Compat module providing :mod:`imghdr` for Python 3.13+.
This is a copy of Python 3.12's :mod:`imghdr` module which was removed in
Python 3.13. It is used by the ``pgpy`` dependency when deriving PGP keys.
"""
from __future__ import annotations
from os import PathLike
import warnings
__all__ = ["what"]
warnings._deprecated(__name__, remove=(3, 13))
# -------------------------
# Recognize image headers
# -------------------------
def what(file, h=None):
"""Return the type of image contained in a file or byte stream."""
f = None
try:
if h is None:
if isinstance(file, (str, PathLike)):
f = open(file, "rb")
h = f.read(32)
else:
location = file.tell()
h = file.read(32)
file.seek(location)
for tf in tests:
res = tf(h, f)
if res:
return res
finally:
if f:
f.close()
return None
# ---------------------------------
# Subroutines per image file type
# ---------------------------------
tests: list = []
def test_jpeg(h, f):
"""Test for JPEG data with JFIF or Exif markers; and raw JPEG."""
if h[6:10] in (b"JFIF", b"Exif"):
return "jpeg"
elif h[:4] == b"\xff\xd8\xff\xdb":
return "jpeg"
tests.append(test_jpeg)
def test_png(h, f):
"""Verify if the image is a PNG."""
if h.startswith(b"\211PNG\r\n\032\n"):
return "png"
tests.append(test_png)
def test_gif(h, f):
"""Verify if the image is a GIF ('87 or '89 variants)."""
if h[:6] in (b"GIF87a", b"GIF89a"):
return "gif"
tests.append(test_gif)
def test_tiff(h, f):
"""Verify if the image is a TIFF (Motorola or Intel)."""
if h[:2] in (b"MM", b"II"):
return "tiff"
tests.append(test_tiff)
def test_rgb(h, f):
"""Test for the SGI image library."""
if h.startswith(b"\001\332"):
return "rgb"
tests.append(test_rgb)
def test_pbm(h, f):
"""Verify if the image is a PBM."""
if len(h) >= 3 and h[0] == ord(b"P") and h[1] in b"14" and h[2] in b" \t\n\r":
return "pbm"
tests.append(test_pbm)
def test_pgm(h, f):
"""Verify if the image is a PGM."""
if len(h) >= 3 and h[0] == ord(b"P") and h[1] in b"25" and h[2] in b" \t\n\r":
return "pgm"
tests.append(test_pgm)
def test_ppm(h, f):
"""Verify if the image is a PPM."""
if len(h) >= 3 and h[0] == ord(b"P") and h[1] in b"36" and h[2] in b" \t\n\r":
return "ppm"
tests.append(test_ppm)
def test_rast(h, f):
"""Test for the Sun raster file."""
if h.startswith(b"\x59\xa6\x6a\x95"):
return "rast"
tests.append(test_rast)
def test_xbm(h, f):
"""Verify if the image is a X bitmap."""
if h.startswith(b"#define "):
return "xbm"
tests.append(test_xbm)
def test_bmp(h, f):
"""Verify if the image is a BMP file."""
if h.startswith(b"BM"):
return "bmp"
tests.append(test_bmp)
def test_webp(h, f):
"""Verify if the image is a WebP."""
if h.startswith(b"RIFF") and h[8:12] == b"WEBP":
return "webp"
tests.append(test_webp)
def test_exr(h, f):
"""Verify if the image is an OpenEXR file."""
if h.startswith(b"\x76\x2f\x31\x01"):
return "exr"
tests.append(test_exr)
# --------------------
# Small test program
# --------------------
def test(): # pragma: no cover - only used for manual testing
import sys
recursive = 0
if sys.argv[1:] and sys.argv[1] == "-r":
del sys.argv[1:2]
recursive = 1
try:
if sys.argv[1:]:
testall(sys.argv[1:], recursive, 1)
else:
testall(["."], recursive, 1)
except KeyboardInterrupt:
sys.stderr.write("\n[Interrupted]\n")
sys.exit(1)
def testall(list, recursive, toplevel): # pragma: no cover - only for manual use
import sys
import os
for filename in list:
if os.path.isdir(filename):
print(filename + "/:", end=" ")
if recursive or toplevel:
print("recursing down:")
import glob
names = glob.glob(os.path.join(glob.escape(filename), "*"))
testall(names, recursive, 0)
else:
print("*** directory (use -r) ***")
else:
print(filename + ":", end=" ")
sys.stdout.flush()
try:
print(what(filename))
except OSError:
print("*** not found ***")
if __name__ == "__main__": # pragma: no cover - manual run
test()