mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-07 14:58:56 +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:
|
||||
raise ValueError("Fingerprint directory not set")
|
||||
self.setup_encryption_manager(self.fingerprint_dir)
|
||||
self.load_parent_seed(self.fingerprint_dir)
|
||||
self.initialize_bip85()
|
||||
self.initialize_managers()
|
||||
self.locked = False
|
||||
@@ -240,7 +239,6 @@ class PasswordManager:
|
||||
sys.exit(1)
|
||||
# Setup the encryption manager and load parent seed
|
||||
self.setup_encryption_manager(self.fingerprint_dir)
|
||||
self.load_parent_seed(self.fingerprint_dir)
|
||||
# Initialize BIP85 and other managers
|
||||
self.initialize_bip85()
|
||||
self.initialize_managers()
|
||||
@@ -257,41 +255,37 @@ class PasswordManager:
|
||||
|
||||
def setup_encryption_manager(
|
||||
self, fingerprint_dir: Path, password: Optional[str] = None
|
||||
):
|
||||
"""
|
||||
Sets up the EncryptionManager for the selected fingerprint.
|
||||
) -> None:
|
||||
"""Set up encryption for the current fingerprint and load the seed."""
|
||||
|
||||
Parameters:
|
||||
fingerprint_dir (Path): The directory corresponding to the fingerprint.
|
||||
password (Optional[str]): The user's master password.
|
||||
"""
|
||||
try:
|
||||
# Prompt for password if not provided
|
||||
if password is None:
|
||||
password = prompt_existing_password("Enter your master password: ")
|
||||
# Derive key using the configured encryption mode if seed is known
|
||||
if self.parent_seed:
|
||||
key = derive_index_key(
|
||||
self.parent_seed,
|
||||
password,
|
||||
self.encryption_mode,
|
||||
)
|
||||
else:
|
||||
key = derive_key_from_password(password)
|
||||
self.encryption_manager = EncryptionManager(key, fingerprint_dir)
|
||||
self.vault = Vault(self.encryption_manager, fingerprint_dir)
|
||||
logger.debug(
|
||||
"EncryptionManager set up successfully for selected fingerprint."
|
||||
|
||||
if not self.parent_seed:
|
||||
seed_key = derive_key_from_password(password)
|
||||
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||
try:
|
||||
self.parent_seed = seed_mgr.decrypt_parent_seed()
|
||||
except Exception:
|
||||
print(colored("Invalid password. Exiting.", "red"))
|
||||
raise
|
||||
|
||||
key = derive_index_key(
|
||||
self.parent_seed,
|
||||
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(
|
||||
vault=self.vault,
|
||||
fingerprint_dir=fingerprint_dir,
|
||||
)
|
||||
|
||||
# Verify the password
|
||||
self.fingerprint_dir = fingerprint_dir # Ensure self.fingerprint_dir is set
|
||||
self.fingerprint_dir = fingerprint_dir
|
||||
if not self.verify_password(password):
|
||||
print(colored("Invalid password. Exiting.", "red"))
|
||||
sys.exit(1)
|
||||
@@ -301,22 +295,23 @@ class PasswordManager:
|
||||
print(colored(f"Error: Failed to set up encryption: {e}", "red"))
|
||||
sys.exit(1)
|
||||
|
||||
def load_parent_seed(self, fingerprint_dir: Path):
|
||||
"""
|
||||
Loads and decrypts the parent seed from the fingerprint directory.
|
||||
def load_parent_seed(
|
||||
self, fingerprint_dir: Path, password: Optional[str] = None
|
||||
) -> 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:
|
||||
self.parent_seed = self.encryption_manager.decrypt_parent_seed()
|
||||
logger.debug(
|
||||
f"Parent seed loaded for fingerprint {self.current_fingerprint}."
|
||||
)
|
||||
# Initialize BIP85 with the parent seed
|
||||
seed_key = derive_key_from_password(password)
|
||||
seed_mgr = EncryptionManager(seed_key, fingerprint_dir)
|
||||
self.parent_seed = seed_mgr.decrypt_parent_seed()
|
||||
seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate()
|
||||
self.bip85 = BIP85(seed_bytes)
|
||||
logger.debug("BIP-85 initialized successfully.")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load parent seed: {e}")
|
||||
logger.error(traceback.format_exc())
|
||||
@@ -364,9 +359,6 @@ class PasswordManager:
|
||||
# Set up the encryption manager with the new password and seed profile directory
|
||||
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
|
||||
self.initialize_bip85()
|
||||
self.initialize_managers()
|
||||
@@ -546,16 +538,19 @@ class PasswordManager:
|
||||
|
||||
# Initialize EncryptionManager with key and fingerprint_dir
|
||||
password = prompt_for_password()
|
||||
key = derive_index_key(
|
||||
index_key = derive_index_key(
|
||||
parent_seed,
|
||||
password,
|
||||
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)
|
||||
|
||||
# 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.")
|
||||
|
||||
# Store the hashed password
|
||||
@@ -678,25 +673,23 @@ class PasswordManager:
|
||||
|
||||
# Prompt for password
|
||||
password = prompt_for_password()
|
||||
# Derive key using the configured encryption mode
|
||||
key = derive_index_key(
|
||||
|
||||
index_key = derive_index_key(
|
||||
seed,
|
||||
password,
|
||||
self.encryption_mode,
|
||||
)
|
||||
seed_key = derive_key_from_password(password)
|
||||
|
||||
# Re-initialize EncryptionManager with the new key and fingerprint_dir
|
||||
self.encryption_manager = EncryptionManager(key, fingerprint_dir)
|
||||
self.encryption_manager = EncryptionManager(index_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)
|
||||
|
||||
# Store the hashed password
|
||||
self.store_hashed_password(password)
|
||||
logging.info("User password hashed and stored successfully.")
|
||||
|
||||
# Encrypt and save the parent seed
|
||||
self.encryption_manager.encrypt_parent_seed(seed)
|
||||
seed_mgr.encrypt_parent_seed(seed)
|
||||
logging.info("Parent seed encrypted and saved successfully.")
|
||||
|
||||
self.parent_seed = seed # Ensure this is a string
|
||||
@@ -1344,12 +1337,14 @@ class PasswordManager:
|
||||
mode,
|
||||
)
|
||||
except Exception:
|
||||
# Fallback for tests or invalid seeds
|
||||
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)
|
||||
|
||||
# Re-encrypt sensitive files using the new manager
|
||||
new_enc_mgr.encrypt_parent_seed(self.parent_seed)
|
||||
seed_mgr.encrypt_parent_seed(self.parent_seed)
|
||||
self.vault.set_encryption_manager(new_enc_mgr)
|
||||
self.vault.save_index(index_data)
|
||||
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