Merge pull request #495 from PR0M3TH3AN/codex/add-orjson-support-to-password-manager

Use compact orjson serialization
This commit is contained in:
thePR0M3TH3AN
2025-07-13 10:49:05 -04:00
committed by GitHub
4 changed files with 39 additions and 8 deletions

View File

@@ -32,6 +32,7 @@ monero==1.1.1
multidict==6.6.3 multidict==6.6.3
mutmut==2.4.4 mutmut==2.4.4
nostr-sdk==0.42.1 nostr-sdk==0.42.1
orjson==3.10.18
packaging==25.0 packaging==25.0
parso==0.8.4 parso==0.8.4
pgpy==0.6.0 pgpy==0.6.0

View File

@@ -2,7 +2,17 @@
import logging import logging
import traceback import traceback
import json
try:
import orjson as json_lib # type: ignore
JSONDecodeError = orjson.JSONDecodeError
USE_ORJSON = True
except Exception: # pragma: no cover - fallback for environments without orjson
import json as json_lib
from json import JSONDecodeError
USE_ORJSON = False
import hashlib import hashlib
import os import os
import base64 import base64
@@ -145,7 +155,10 @@ class EncryptionManager:
def save_json_data(self, data: dict, relative_path: Optional[Path] = None) -> None: def save_json_data(self, data: dict, relative_path: Optional[Path] = None) -> None:
if relative_path is None: if relative_path is None:
relative_path = Path("seedpass_entries_db.json.enc") relative_path = Path("seedpass_entries_db.json.enc")
json_data = json.dumps(data, indent=4).encode("utf-8") if USE_ORJSON:
json_data = json_lib.dumps(data)
else:
json_data = json_lib.dumps(data, separators=(",", ":")).encode("utf-8")
self.encrypt_and_save_file(json_data, relative_path) self.encrypt_and_save_file(json_data, relative_path)
logger.debug(f"JSON data encrypted and saved to '{relative_path}'.") logger.debug(f"JSON data encrypted and saved to '{relative_path}'.")
@@ -169,7 +182,10 @@ class EncryptionManager:
try: try:
decrypted_data = self.decrypt_data(encrypted_data) decrypted_data = self.decrypt_data(encrypted_data)
data = json.loads(decrypted_data.decode("utf-8")) if USE_ORJSON:
data = json_lib.loads(decrypted_data)
else:
data = json_lib.loads(decrypted_data.decode("utf-8"))
# If it was a legacy file, re-save it in the new format now # If it was a legacy file, re-save it in the new format now
if is_legacy: if is_legacy:
@@ -178,7 +194,7 @@ class EncryptionManager:
self.update_checksum(relative_path) self.update_checksum(relative_path)
return data return data
except (InvalidToken, InvalidTag, json.JSONDecodeError) as e: except (InvalidToken, InvalidTag, JSONDecodeError) as e:
logger.error( logger.error(
f"FATAL: Could not decrypt or parse data from {file_path}: {e}", f"FATAL: Could not decrypt or parse data from {file_path}: {e}",
exc_info=True, exc_info=True,
@@ -204,7 +220,10 @@ class EncryptionManager:
decrypted_data = self.decrypt_data( decrypted_data = self.decrypt_data(
encrypted_data encrypted_data
) # This now handles both formats ) # This now handles both formats
data = json.loads(decrypted_data.decode("utf-8")) if USE_ORJSON:
data = json_lib.loads(decrypted_data)
else:
data = json_lib.loads(decrypted_data.decode("utf-8"))
self.save_json_data(data, relative_path) # This always saves in V2 format self.save_json_data(data, relative_path) # This always saves in V2 format
self.update_checksum(relative_path) self.update_checksum(relative_path)
logger.info("Index file from Nostr was processed and saved successfully.") logger.info("Index file from Nostr was processed and saved successfully.")

View File

@@ -15,7 +15,14 @@ completely deterministic passwords from a BIP-85 seed, ensuring that passwords a
the same way every time. Salts would break this functionality and are not suitable for this software. the same way every time. Salts would break this functionality and are not suitable for this software.
""" """
import json try:
import orjson as json_lib # type: ignore
USE_ORJSON = True
except Exception: # pragma: no cover - fallback when orjson is missing
import json as json_lib
USE_ORJSON = False
import logging import logging
import hashlib import hashlib
import sys import sys
@@ -1155,8 +1162,11 @@ class EntryManager:
""" """
try: try:
data = self._load_index() data = self._load_index()
json_content = json.dumps(data, indent=4) if USE_ORJSON:
checksum = hashlib.sha256(json_content.encode("utf-8")).hexdigest() json_bytes = json_lib.dumps(data)
else:
json_bytes = json_lib.dumps(data, separators=(",", ":")).encode("utf-8")
checksum = hashlib.sha256(json_bytes).hexdigest()
# The checksum file path already includes the fingerprint directory # The checksum file path already includes the fingerprint directory
checksum_path = self.checksum_file checksum_path = self.checksum_file

View File

@@ -30,3 +30,4 @@ uvicorn>=0.35.0
httpx>=0.28.1 httpx>=0.28.1
requests>=2.32 requests>=2.32
python-multipart python-multipart
orjson