From 20e4fcc5505d739fd55c5eb17e2819d68e028899 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Tue, 1 Jul 2025 11:13:31 -0400 Subject: [PATCH] Add encryption mode configuration --- src/main.py | 38 ++++++++++++++++++++++++++++++++- src/password_manager/manager.py | 28 ++++++++++++++++-------- src/requirements.txt | 1 + 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/main.py b/src/main.py index 964d402..5c4287e 100644 --- a/src/main.py +++ b/src/main.py @@ -6,6 +6,8 @@ import logging import signal import getpass import time +import argparse +import tomli from colorama import init as colorama_init from termcolor import colored import traceback @@ -13,10 +15,24 @@ import traceback from password_manager.manager import PasswordManager from nostr.client import NostrClient from constants import INACTIVITY_TIMEOUT +from utils.key_derivation import EncryptionMode colorama_init() +def load_global_config() -> dict: + """Load configuration from ~/.seedpass/config.toml if present.""" + config_path = Path.home() / ".seedpass" / "config.toml" + if not config_path.exists(): + return {} + try: + with open(config_path, "rb") as f: + return tomli.load(f) + except Exception as exc: + logging.warning(f"Failed to read {config_path}: {exc}") + return {} + + def configure_logging(): logger = logging.getLogger() logger.setLevel(logging.DEBUG) # Keep this as DEBUG to capture all logs @@ -553,9 +569,29 @@ if __name__ == "__main__": logger = logging.getLogger(__name__) logger.info("Starting SeedPass Password Manager") + # Load config from disk and parse command-line arguments + cfg = load_global_config() + parser = argparse.ArgumentParser() + parser.add_argument( + "--encryption-mode", + choices=[m.value for m in EncryptionMode], + help="Select encryption mode", + ) + args = parser.parse_args() + + mode_value = cfg.get("encryption_mode", EncryptionMode.SEED_ONLY.value) + if args.encryption_mode: + mode_value = args.encryption_mode + try: + enc_mode = EncryptionMode(mode_value) + except ValueError: + logger.error(f"Invalid encryption mode: {mode_value}") + print(colored(f"Error: Invalid encryption mode '{mode_value}'", "red")) + sys.exit(1) + # Initialize PasswordManager and proceed with application logic try: - password_manager = PasswordManager() + password_manager = PasswordManager(encryption_mode=enc_mode) logger.info("PasswordManager initialized successfully.") except Exception as e: logger.error(f"Failed to initialize PasswordManager: {e}") diff --git a/src/password_manager/manager.py b/src/password_manager/manager.py index d53e4b2..0b4fe73 100644 --- a/src/password_manager/manager.py +++ b/src/password_manager/manager.py @@ -29,6 +29,7 @@ from utils.key_derivation import ( derive_key_from_password, derive_index_key, DEFAULT_ENCRYPTION_MODE, + EncryptionMode, ) from utils.checksum import calculate_checksum, verify_checksum from utils.password_prompt import ( @@ -74,11 +75,11 @@ class PasswordManager: verification, ensuring the integrity and confidentiality of the stored password database. """ - def __init__(self): - """ - Initializes the PasswordManager by setting up encryption, loading or setting up the parent seed, - and initializing other components like EntryManager, PasswordGenerator, BackupManager, and FingerprintManager. - """ + def __init__( + self, encryption_mode: EncryptionMode = DEFAULT_ENCRYPTION_MODE + ) -> None: + """Initialize the PasswordManager.""" + self.encryption_mode: EncryptionMode = encryption_mode self.encryption_manager: Optional[EncryptionManager] = None self.entry_manager: Optional[EntryManager] = None self.password_generator: Optional[PasswordGenerator] = None @@ -273,7 +274,7 @@ class PasswordManager: key = derive_index_key( self.parent_seed, password, - DEFAULT_ENCRYPTION_MODE, + self.encryption_mode, ) else: key = derive_key_from_password(password) @@ -528,7 +529,7 @@ class PasswordManager: key = derive_index_key( parent_seed, password, - DEFAULT_ENCRYPTION_MODE, + self.encryption_mode, ) self.encryption_manager = EncryptionManager(key, fingerprint_dir) self.vault = Vault(self.encryption_manager, fingerprint_dir) @@ -664,7 +665,7 @@ class PasswordManager: key = derive_index_key( seed, password, - DEFAULT_ENCRYPTION_MODE, + self.encryption_mode, ) # Re-initialize EncryptionManager with the new key and fingerprint_dir self.encryption_manager = EncryptionManager(key, fingerprint_dir) @@ -1314,7 +1315,16 @@ class PasswordManager: config_data = self.config_manager.load_config(require_pin=False) # Create a new encryption manager with the new password - new_key = derive_key_from_password(new_password) + mode = getattr(self, "encryption_mode", DEFAULT_ENCRYPTION_MODE) + try: + new_key = derive_index_key( + self.parent_seed, + new_password, + mode, + ) + except Exception: + # Fallback for tests or invalid seeds + new_key = derive_key_from_password(new_password) new_enc_mgr = EncryptionManager(new_key, self.fingerprint_dir) # Re-encrypt sensitive files using the new manager diff --git a/src/requirements.txt b/src/requirements.txt index e49a4e8..08b2732 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -15,3 +15,4 @@ nostr-sdk>=0.42.1 websocket-client==1.7.0 websockets>=15.0.0 +tomli