mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-08 07:18:47 +00:00
Merge pull request #97 from PR0M3TH3AN/codex/fix-password-reset-issue-and-add-test
Fix unlock after password change
This commit is contained in:
@@ -128,7 +128,6 @@ class PasswordManager:
|
|||||||
if not self.fingerprint_dir:
|
if not self.fingerprint_dir:
|
||||||
raise ValueError("Fingerprint directory not set")
|
raise ValueError("Fingerprint directory not set")
|
||||||
self.setup_encryption_manager(self.fingerprint_dir)
|
self.setup_encryption_manager(self.fingerprint_dir)
|
||||||
self.load_parent_seed(self.fingerprint_dir)
|
|
||||||
self.initialize_bip85()
|
self.initialize_bip85()
|
||||||
self.initialize_managers()
|
self.initialize_managers()
|
||||||
self.locked = False
|
self.locked = False
|
||||||
@@ -240,7 +239,6 @@ class PasswordManager:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# Setup the encryption manager and load parent seed
|
# Setup the encryption manager and load parent seed
|
||||||
self.setup_encryption_manager(self.fingerprint_dir)
|
self.setup_encryption_manager(self.fingerprint_dir)
|
||||||
self.load_parent_seed(self.fingerprint_dir)
|
|
||||||
# Initialize BIP85 and other managers
|
# Initialize BIP85 and other managers
|
||||||
self.initialize_bip85()
|
self.initialize_bip85()
|
||||||
self.initialize_managers()
|
self.initialize_managers()
|
||||||
@@ -257,41 +255,37 @@ class PasswordManager:
|
|||||||
|
|
||||||
def setup_encryption_manager(
|
def setup_encryption_manager(
|
||||||
self, fingerprint_dir: Path, password: Optional[str] = None
|
self, fingerprint_dir: Path, password: Optional[str] = None
|
||||||
):
|
) -> None:
|
||||||
"""
|
"""Set up encryption for the current fingerprint and load the seed."""
|
||||||
Sets up the EncryptionManager for the selected fingerprint.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
fingerprint_dir (Path): The directory corresponding to the fingerprint.
|
|
||||||
password (Optional[str]): The user's master password.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
# Prompt for password if not provided
|
|
||||||
if password is None:
|
if password is None:
|
||||||
password = prompt_existing_password("Enter your master password: ")
|
password = prompt_existing_password("Enter your master password: ")
|
||||||
# Derive key using the configured encryption mode if seed is known
|
|
||||||
if self.parent_seed:
|
if not self.parent_seed:
|
||||||
key = derive_index_key(
|
seed_key = derive_key_from_password(password)
|
||||||
self.parent_seed,
|
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||||
password,
|
try:
|
||||||
self.encryption_mode,
|
self.parent_seed = seed_mgr.decrypt_parent_seed()
|
||||||
)
|
except Exception:
|
||||||
else:
|
print(colored("Invalid password. Exiting.", "red"))
|
||||||
key = derive_key_from_password(password)
|
raise
|
||||||
self.encryption_manager = EncryptionManager(key, fingerprint_dir)
|
|
||||||
self.vault = Vault(self.encryption_manager, fingerprint_dir)
|
key = derive_index_key(
|
||||||
logger.debug(
|
self.parent_seed,
|
||||||
"EncryptionManager set up successfully for selected fingerprint."
|
password,
|
||||||
|
self.encryption_mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Initialize ConfigManager before verifying password
|
self.encryption_manager = EncryptionManager(key, fingerprint_dir)
|
||||||
|
self.vault = Vault(self.encryption_manager, fingerprint_dir)
|
||||||
|
|
||||||
self.config_manager = ConfigManager(
|
self.config_manager = ConfigManager(
|
||||||
vault=self.vault,
|
vault=self.vault,
|
||||||
fingerprint_dir=fingerprint_dir,
|
fingerprint_dir=fingerprint_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Verify the password
|
self.fingerprint_dir = fingerprint_dir
|
||||||
self.fingerprint_dir = fingerprint_dir # Ensure self.fingerprint_dir is set
|
|
||||||
if not self.verify_password(password):
|
if not self.verify_password(password):
|
||||||
print(colored("Invalid password. Exiting.", "red"))
|
print(colored("Invalid password. Exiting.", "red"))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -301,22 +295,23 @@ class PasswordManager:
|
|||||||
print(colored(f"Error: Failed to set up encryption: {e}", "red"))
|
print(colored(f"Error: Failed to set up encryption: {e}", "red"))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def load_parent_seed(self, fingerprint_dir: Path):
|
def load_parent_seed(
|
||||||
"""
|
self, fingerprint_dir: Path, password: Optional[str] = None
|
||||||
Loads and decrypts the parent seed from the fingerprint directory.
|
) -> None:
|
||||||
|
"""Load and decrypt the parent seed using the password-only key."""
|
||||||
|
|
||||||
|
if self.parent_seed:
|
||||||
|
return
|
||||||
|
|
||||||
|
if password is None:
|
||||||
|
password = prompt_existing_password("Enter your master password: ")
|
||||||
|
|
||||||
Parameters:
|
|
||||||
fingerprint_dir (Path): The directory corresponding to the fingerprint.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
self.parent_seed = self.encryption_manager.decrypt_parent_seed()
|
seed_key = derive_key_from_password(password)
|
||||||
logger.debug(
|
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||||
f"Parent seed loaded for fingerprint {self.current_fingerprint}."
|
self.parent_seed = seed_mgr.decrypt_parent_seed()
|
||||||
)
|
|
||||||
# Initialize BIP85 with the parent seed
|
|
||||||
seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate()
|
seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate()
|
||||||
self.bip85 = BIP85(seed_bytes)
|
self.bip85 = BIP85(seed_bytes)
|
||||||
logger.debug("BIP-85 initialized successfully.")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to load parent seed: {e}")
|
logger.error(f"Failed to load parent seed: {e}")
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
@@ -364,9 +359,6 @@ class PasswordManager:
|
|||||||
# Set up the encryption manager with the new password and seed profile directory
|
# Set up the encryption manager with the new password and seed profile directory
|
||||||
self.setup_encryption_manager(self.fingerprint_dir, password)
|
self.setup_encryption_manager(self.fingerprint_dir, password)
|
||||||
|
|
||||||
# Load the parent seed for the selected seed profile
|
|
||||||
self.load_parent_seed(self.fingerprint_dir)
|
|
||||||
|
|
||||||
# Initialize BIP85 and other managers
|
# Initialize BIP85 and other managers
|
||||||
self.initialize_bip85()
|
self.initialize_bip85()
|
||||||
self.initialize_managers()
|
self.initialize_managers()
|
||||||
@@ -546,16 +538,19 @@ class PasswordManager:
|
|||||||
|
|
||||||
# Initialize EncryptionManager with key and fingerprint_dir
|
# Initialize EncryptionManager with key and fingerprint_dir
|
||||||
password = prompt_for_password()
|
password = prompt_for_password()
|
||||||
key = derive_index_key(
|
index_key = derive_index_key(
|
||||||
parent_seed,
|
parent_seed,
|
||||||
password,
|
password,
|
||||||
self.encryption_mode,
|
self.encryption_mode,
|
||||||
)
|
)
|
||||||
self.encryption_manager = EncryptionManager(key, fingerprint_dir)
|
seed_key = derive_key_from_password(password)
|
||||||
|
|
||||||
|
self.encryption_manager = EncryptionManager(index_key, fingerprint_dir)
|
||||||
|
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||||
self.vault = Vault(self.encryption_manager, fingerprint_dir)
|
self.vault = Vault(self.encryption_manager, fingerprint_dir)
|
||||||
|
|
||||||
# Encrypt and save the parent seed
|
# Encrypt and save the parent seed
|
||||||
self.encryption_manager.encrypt_parent_seed(parent_seed)
|
seed_mgr.encrypt_parent_seed(parent_seed)
|
||||||
logging.info("Parent seed encrypted and saved successfully.")
|
logging.info("Parent seed encrypted and saved successfully.")
|
||||||
|
|
||||||
# Store the hashed password
|
# Store the hashed password
|
||||||
@@ -678,25 +673,23 @@ class PasswordManager:
|
|||||||
|
|
||||||
# Prompt for password
|
# Prompt for password
|
||||||
password = prompt_for_password()
|
password = prompt_for_password()
|
||||||
# Derive key using the configured encryption mode
|
|
||||||
key = derive_index_key(
|
index_key = derive_index_key(
|
||||||
seed,
|
seed,
|
||||||
password,
|
password,
|
||||||
self.encryption_mode,
|
self.encryption_mode,
|
||||||
)
|
)
|
||||||
|
seed_key = derive_key_from_password(password)
|
||||||
|
|
||||||
# Re-initialize EncryptionManager with the new key and fingerprint_dir
|
self.encryption_manager = EncryptionManager(index_key, fingerprint_dir)
|
||||||
self.encryption_manager = EncryptionManager(key, fingerprint_dir)
|
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||||
|
|
||||||
# Initialize the vault now that encryption manager is available
|
|
||||||
self.vault = Vault(self.encryption_manager, fingerprint_dir)
|
self.vault = Vault(self.encryption_manager, fingerprint_dir)
|
||||||
|
|
||||||
# Store the hashed password
|
|
||||||
self.store_hashed_password(password)
|
self.store_hashed_password(password)
|
||||||
logging.info("User password hashed and stored successfully.")
|
logging.info("User password hashed and stored successfully.")
|
||||||
|
|
||||||
# Encrypt and save the parent seed
|
seed_mgr.encrypt_parent_seed(seed)
|
||||||
self.encryption_manager.encrypt_parent_seed(seed)
|
|
||||||
logging.info("Parent seed encrypted and saved successfully.")
|
logging.info("Parent seed encrypted and saved successfully.")
|
||||||
|
|
||||||
self.parent_seed = seed # Ensure this is a string
|
self.parent_seed = seed # Ensure this is a string
|
||||||
@@ -1344,12 +1337,14 @@ class PasswordManager:
|
|||||||
mode,
|
mode,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
# Fallback for tests or invalid seeds
|
|
||||||
new_key = derive_key_from_password(new_password)
|
new_key = derive_key_from_password(new_password)
|
||||||
|
|
||||||
|
seed_key = derive_key_from_password(new_password)
|
||||||
|
seed_mgr = EncryptionManager(seed_key, self.fingerprint_dir)
|
||||||
|
|
||||||
new_enc_mgr = EncryptionManager(new_key, self.fingerprint_dir)
|
new_enc_mgr = EncryptionManager(new_key, self.fingerprint_dir)
|
||||||
|
|
||||||
# Re-encrypt sensitive files using the new manager
|
seed_mgr.encrypt_parent_seed(self.parent_seed)
|
||||||
new_enc_mgr.encrypt_parent_seed(self.parent_seed)
|
|
||||||
self.vault.set_encryption_manager(new_enc_mgr)
|
self.vault.set_encryption_manager(new_enc_mgr)
|
||||||
self.vault.save_index(index_data)
|
self.vault.save_index(index_data)
|
||||||
self.config_manager.vault = self.vault
|
self.config_manager.vault = self.vault
|
||||||
|
85
src/tests/test_password_unlock_after_change.py
Normal file
85
src/tests/test_password_unlock_after_change.py
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
import bcrypt
|
||||||
|
|
||||||
|
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
||||||
|
|
||||||
|
from password_manager.encryption import EncryptionManager
|
||||||
|
from password_manager.vault import Vault
|
||||||
|
from password_manager.entry_management import EntryManager
|
||||||
|
from password_manager.config_manager import ConfigManager
|
||||||
|
from password_manager.manager import PasswordManager, EncryptionMode
|
||||||
|
from utils.key_derivation import derive_index_key, derive_key_from_password
|
||||||
|
|
||||||
|
SEED = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
||||||
|
|
||||||
|
|
||||||
|
def test_password_change_and_unlock(monkeypatch):
|
||||||
|
with TemporaryDirectory() as tmpdir:
|
||||||
|
fp = Path(tmpdir)
|
||||||
|
old_pw = "oldpw"
|
||||||
|
new_pw = "newpw"
|
||||||
|
|
||||||
|
# initial encryption setup
|
||||||
|
index_key = derive_index_key(SEED, old_pw, EncryptionMode.SEED_PLUS_PW)
|
||||||
|
seed_key = derive_key_from_password(old_pw)
|
||||||
|
enc_mgr = EncryptionManager(index_key, fp)
|
||||||
|
seed_mgr = EncryptionManager(seed_key, fp)
|
||||||
|
vault = Vault(enc_mgr, fp)
|
||||||
|
entry_mgr = EntryManager(vault, fp)
|
||||||
|
cfg_mgr = ConfigManager(vault, fp)
|
||||||
|
|
||||||
|
vault.save_index({"passwords": {}})
|
||||||
|
cfg_mgr.save_config(
|
||||||
|
{
|
||||||
|
"relays": [],
|
||||||
|
"pin_hash": "",
|
||||||
|
"password_hash": bcrypt.hashpw(
|
||||||
|
old_pw.encode(), bcrypt.gensalt()
|
||||||
|
).decode(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
seed_mgr.encrypt_parent_seed(SEED)
|
||||||
|
|
||||||
|
pm = PasswordManager.__new__(PasswordManager)
|
||||||
|
pm.encryption_mode = EncryptionMode.SEED_PLUS_PW
|
||||||
|
pm.encryption_manager = enc_mgr
|
||||||
|
pm.entry_manager = entry_mgr
|
||||||
|
pm.config_manager = cfg_mgr
|
||||||
|
pm.vault = vault
|
||||||
|
pm.password_generator = SimpleNamespace(encryption_manager=enc_mgr)
|
||||||
|
pm.fingerprint_dir = fp
|
||||||
|
pm.current_fingerprint = "fp"
|
||||||
|
pm.parent_seed = SEED
|
||||||
|
pm.nostr_client = SimpleNamespace(publish_json_to_nostr=lambda *a, **k: None)
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"password_manager.manager.prompt_existing_password", lambda *_: old_pw
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"password_manager.manager.prompt_for_password", lambda: new_pw
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"password_manager.manager.NostrClient",
|
||||||
|
lambda *a, **kw: SimpleNamespace(
|
||||||
|
publish_json_to_nostr=lambda *a, **k: None
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
pm.change_password()
|
||||||
|
pm.lock_vault()
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"password_manager.manager.prompt_existing_password", lambda *_: new_pw
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(PasswordManager, "initialize_bip85", lambda self: None)
|
||||||
|
monkeypatch.setattr(PasswordManager, "initialize_managers", lambda self: None)
|
||||||
|
|
||||||
|
pm.unlock_vault()
|
||||||
|
|
||||||
|
assert pm.parent_seed == SEED
|
||||||
|
assert pm.verify_password(new_pw)
|
||||||
|
assert not pm.locked
|
Reference in New Issue
Block a user