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

View File

@@ -30,6 +30,15 @@ from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from bip_utils import Bip39SeedGenerator 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 local_bip85.bip85 import BIP85
from constants import DEFAULT_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH 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 # interrupt the loop after first iteration
monkeypatch.setattr( monkeypatch.setattr(
"password_manager.manager.select.select", "password_manager.manager.timed_input",
lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()), lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()),
) )
@@ -91,7 +91,7 @@ def test_display_totp_codes_excludes_blacklisted(monkeypatch, capsys):
) )
monkeypatch.setattr( monkeypatch.setattr(
"password_manager.manager.select.select", "password_manager.manager.timed_input",
lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()), 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 pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 1
) )
monkeypatch.setattr("password_manager.manager.time.sleep", lambda *a, **k: None) monkeypatch.setattr("password_manager.manager.time.sleep", lambda *a, **k: None)
monkeypatch.setattr(sys.stdin, "readline", lambda *a, **k: "b\n")
monkeypatch.setattr( monkeypatch.setattr(
"password_manager.manager.select.select", "password_manager.manager.timed_input",
lambda *a, **k: ([sys.stdin], [], []), lambda *a, **k: "b",
) )
inputs = iter(["1", "0"]) 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 pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 1
) )
monkeypatch.setattr("password_manager.manager.time.sleep", lambda *a, **k: None) monkeypatch.setattr("password_manager.manager.time.sleep", lambda *a, **k: None)
monkeypatch.setattr(sys.stdin, "readline", lambda *a, **k: "b\n")
monkeypatch.setattr( monkeypatch.setattr(
"password_manager.manager.select.select", "password_manager.manager.timed_input",
lambda *a, **k: ([sys.stdin], [], []), lambda *a, **k: "b",
) )
pm.handle_retrieve_entry() 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 pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30
) )
monkeypatch.setattr( monkeypatch.setattr(
"password_manager.manager.select.select", "password_manager.manager.timed_input",
lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()), lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()),
) )
called = [] 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 pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30
) )
monkeypatch.setattr( monkeypatch.setattr(
"password_manager.manager.select.select", "password_manager.manager.timed_input",
lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()), lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()),
) )
called = [] 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()