Merge pull request #125 from PR0M3TH3AN/codex/update-vault-test-setups-for-encryption

Use password derived keys in tests
This commit is contained in:
thePR0M3TH3AN
2025-07-01 22:47:15 -04:00
committed by GitHub
15 changed files with 85 additions and 92 deletions

32
src/tests/helpers.py Normal file
View File

@@ -0,0 +1,32 @@
import sys
from pathlib import Path
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.vault import Vault
from password_manager.encryption import EncryptionManager
from utils.key_derivation import (
derive_index_key,
derive_key_from_password,
EncryptionMode,
)
TEST_SEED = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
TEST_PASSWORD = "pw"
def create_vault(
dir_path: Path,
seed: str = TEST_SEED,
password: str = TEST_PASSWORD,
mode: EncryptionMode = EncryptionMode.SEED_ONLY,
) -> tuple[Vault, EncryptionManager]:
"""Create a Vault initialized for tests."""
seed_key = derive_key_from_password(password)
seed_mgr = EncryptionManager(seed_key, dir_path)
seed_mgr.encrypt_parent_seed(seed)
index_key = derive_index_key(seed, password, mode)
enc_mgr = EncryptionManager(index_key, dir_path)
vault = Vault(enc_mgr, dir_path)
return vault, enc_mgr

View File

@@ -4,21 +4,17 @@ import time
from pathlib import Path
from tempfile import TemporaryDirectory
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.vault import Vault
from password_manager.backup import BackupManager
def test_backup_restore_workflow(monkeypatch):
with TemporaryDirectory() as tmpdir:
fp_dir = Path(tmpdir)
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, fp_dir)
vault = Vault(enc_mgr, fp_dir)
vault, enc_mgr = create_vault(fp_dir, TEST_SEED, TEST_PASSWORD)
backup_mgr = BackupManager(fp_dir)
index_file = fp_dir / "seedpass_passwords_db.json.enc"

View File

@@ -1,19 +1,24 @@
import sys
from pathlib import Path
from multiprocessing import Process, Queue
from cryptography.fernet import Fernet
import pytest
from helpers import TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.vault import Vault
from password_manager.backup import BackupManager
from utils.key_derivation import (
derive_index_key,
derive_key_from_password,
EncryptionMode,
)
def _writer(key: bytes, dir_path: Path, loops: int, out: Queue) -> None:
def _writer(index_key: bytes, dir_path: Path, loops: int, out: Queue) -> None:
try:
enc = EncryptionManager(key, dir_path)
enc = EncryptionManager(index_key, dir_path)
vault = Vault(enc, dir_path)
for _ in range(loops):
data = vault.load_index()
@@ -23,9 +28,9 @@ def _writer(key: bytes, dir_path: Path, loops: int, out: Queue) -> None:
out.put(repr(e))
def _reader(key: bytes, dir_path: Path, loops: int, out: Queue) -> None:
def _reader(index_key: bytes, dir_path: Path, loops: int, out: Queue) -> None:
try:
enc = EncryptionManager(key, dir_path)
enc = EncryptionManager(index_key, dir_path)
vault = Vault(enc, dir_path)
for _ in range(loops):
vault.load_index()
@@ -45,16 +50,18 @@ def _backup(dir_path: Path, loops: int, out: Queue) -> None:
@pytest.mark.parametrize("loops", [5, pytest.param(20, marks=pytest.mark.stress)])
@pytest.mark.parametrize("_", range(3))
def test_concurrency_stress(tmp_path: Path, loops: int, _):
key = Fernet.generate_key()
enc = EncryptionManager(key, tmp_path)
index_key = derive_index_key(TEST_SEED, TEST_PASSWORD, EncryptionMode.SEED_ONLY)
seed_key = derive_key_from_password(TEST_PASSWORD)
EncryptionManager(seed_key, tmp_path).encrypt_parent_seed(TEST_SEED)
enc = EncryptionManager(index_key, tmp_path)
Vault(enc, tmp_path).save_index({"counter": 0})
q: Queue = Queue()
procs = [
Process(target=_writer, args=(key, tmp_path, loops, q)),
Process(target=_writer, args=(key, tmp_path, loops, q)),
Process(target=_reader, args=(key, tmp_path, loops, q)),
Process(target=_reader, args=(key, tmp_path, loops, q)),
Process(target=_writer, args=(index_key, tmp_path, loops, q)),
Process(target=_writer, args=(index_key, tmp_path, loops, q)),
Process(target=_reader, args=(index_key, tmp_path, loops, q)),
Process(target=_reader, args=(index_key, tmp_path, loops, q)),
Process(target=_backup, args=(tmp_path, loops, q)),
]
@@ -69,5 +76,5 @@ def test_concurrency_stress(tmp_path: Path, loops: int, _):
assert not errors
vault = Vault(EncryptionManager(key, tmp_path), tmp_path)
vault = Vault(EncryptionManager(index_key, tmp_path), tmp_path)
assert isinstance(vault.load_index(), dict)

View File

@@ -1,13 +1,12 @@
import bcrypt
from pathlib import Path
from tempfile import TemporaryDirectory
from cryptography.fernet import Fernet
import pytest
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
import sys
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.config_manager import ConfigManager
from password_manager.vault import Vault
from nostr.client import DEFAULT_RELAYS
@@ -15,9 +14,7 @@ from nostr.client import DEFAULT_RELAYS
def test_config_defaults_and_round_trip():
with TemporaryDirectory() as tmpdir:
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, Path(tmpdir))
vault = Vault(enc_mgr, Path(tmpdir))
vault, enc_mgr = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, Path(tmpdir))
cfg = cfg_mgr.load_config(require_pin=False)
@@ -35,9 +32,7 @@ def test_config_defaults_and_round_trip():
def test_pin_verification_and_change():
with TemporaryDirectory() as tmpdir:
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, Path(tmpdir))
vault = Vault(enc_mgr, Path(tmpdir))
vault, enc_mgr = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, Path(tmpdir))
cfg_mgr.set_pin("1234")
@@ -52,9 +47,7 @@ import json
def test_config_file_encrypted_after_save():
with TemporaryDirectory() as tmpdir:
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, Path(tmpdir))
vault = Vault(enc_mgr, Path(tmpdir))
vault, enc_mgr = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, Path(tmpdir))
data = {"relays": ["wss://r"], "pin_hash": ""}
@@ -72,9 +65,7 @@ def test_config_file_encrypted_after_save():
def test_set_relays_persists_changes():
with TemporaryDirectory() as tmpdir:
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, Path(tmpdir))
vault = Vault(enc_mgr, Path(tmpdir))
vault, enc_mgr = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, Path(tmpdir))
cfg_mgr.set_relays(["wss://custom"], require_pin=False)
cfg = cfg_mgr.load_config(require_pin=False)
@@ -83,18 +74,14 @@ def test_set_relays_persists_changes():
def test_set_relays_requires_at_least_one():
with TemporaryDirectory() as tmpdir:
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, Path(tmpdir))
vault = Vault(enc_mgr, Path(tmpdir))
vault, enc_mgr = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, Path(tmpdir))
with pytest.raises(ValueError):
cfg_mgr.set_relays([], require_pin=False)
def test_password_hash_migrates_from_file(tmp_path):
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, tmp_path)
vault = Vault(enc_mgr, tmp_path)
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, tmp_path)
# save legacy config without password_hash

View File

@@ -1,20 +1,17 @@
import sys
from pathlib import Path
from tempfile import TemporaryDirectory
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.entry_management import EntryManager
from password_manager.vault import Vault
def test_list_entries_empty():
with TemporaryDirectory() as tmpdir:
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, Path(tmpdir))
vault = Vault(enc_mgr, Path(tmpdir))
vault, enc_mgr = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
entry_mgr = EntryManager(vault, Path(tmpdir))
entries = entry_mgr.list_entries()

View File

@@ -1,20 +1,17 @@
import sys
from pathlib import Path
from tempfile import TemporaryDirectory
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.entry_management import EntryManager
from password_manager.vault import Vault
def test_add_and_retrieve_entry():
with TemporaryDirectory() as tmpdir:
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, Path(tmpdir))
vault = Vault(enc_mgr, Path(tmpdir))
vault, enc_mgr = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
entry_mgr = EntryManager(vault, Path(tmpdir))
index = entry_mgr.add_entry("example.com", 12, "user")

View File

@@ -1,21 +1,18 @@
import sys
from pathlib import Path
from tempfile import TemporaryDirectory
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
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.vault import Vault
def test_update_checksum_writes_to_expected_path():
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, tmp_path)
vault = Vault(enc_mgr, tmp_path)
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
entry_mgr = EntryManager(vault, tmp_path)
# create an empty index file
@@ -29,9 +26,7 @@ def test_update_checksum_writes_to_expected_path():
def test_backup_index_file_creates_backup_in_directory():
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, tmp_path)
vault = Vault(enc_mgr, tmp_path)
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
entry_mgr = EntryManager(vault, tmp_path)
vault.save_index({"passwords": {}})

View File

@@ -3,7 +3,7 @@ from tempfile import TemporaryDirectory
import pytest
import sys
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
@@ -56,7 +56,5 @@ def test_index_export_import_round_trip(mode):
def test_get_encrypted_index_missing_file(tmp_path):
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, tmp_path)
vault = Vault(enc_mgr, tmp_path)
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
assert vault.get_encrypted_index() is None

View File

@@ -1,11 +1,10 @@
import sys
from pathlib import Path
from tempfile import TemporaryDirectory
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.entry_management import EntryManager
from password_manager.vault import Vault
from password_manager.backup import BackupManager
@@ -29,9 +28,7 @@ class FakeNostrClient:
def test_manager_workflow(monkeypatch):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, tmp_path)
vault = Vault(enc_mgr, tmp_path)
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
entry_mgr = EntryManager(vault, tmp_path)
backup_mgr = BackupManager(tmp_path)

View File

@@ -1,19 +1,15 @@
import sys
from pathlib import Path
import pytest
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.vault import Vault
from password_manager.migrations import LATEST_VERSION
def setup(tmp_path: Path):
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, tmp_path)
vault = Vault(enc_mgr, tmp_path)
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
return enc_mgr, vault

View File

@@ -2,11 +2,10 @@ import sys
from pathlib import Path
from tempfile import TemporaryDirectory
from unittest.mock import patch
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.entry_management import EntryManager
from password_manager.vault import Vault
from nostr.client import NostrClient
@@ -15,9 +14,7 @@ from nostr.client import NostrClient
def test_backup_and_publish_to_nostr():
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, tmp_path)
vault = Vault(enc_mgr, tmp_path)
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
entry_mgr = EntryManager(vault, tmp_path)
# create an index by adding an entry

View File

@@ -4,11 +4,10 @@ from tempfile import TemporaryDirectory
from types import SimpleNamespace
from unittest.mock import patch
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
from password_manager.encryption import EncryptionManager
from password_manager.entry_management import EntryManager
from password_manager.config_manager import ConfigManager
from password_manager.vault import Vault
@@ -18,8 +17,7 @@ from password_manager.manager import PasswordManager
def test_change_password_triggers_nostr_backup(monkeypatch):
with TemporaryDirectory() as tmpdir:
fp = Path(tmpdir)
enc_mgr = EncryptionManager(Fernet.generate_key(), fp)
vault = Vault(enc_mgr, fp)
vault, enc_mgr = create_vault(fp, TEST_SEED, TEST_PASSWORD)
entry_mgr = EntryManager(vault, fp)
cfg_mgr = ConfigManager(vault, fp)

View File

@@ -4,7 +4,7 @@ from pathlib import Path
from tempfile import TemporaryDirectory
from types import SimpleNamespace
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
@@ -12,7 +12,6 @@ sys.path.append(str(Path(__file__).resolve().parents[1]))
from utils.fingerprint_manager import FingerprintManager
import constants
import password_manager.manager as manager_module
from password_manager.encryption import EncryptionManager
from password_manager.vault import Vault
from password_manager.entry_management import EntryManager
@@ -49,9 +48,7 @@ def test_add_and_delete_entry(monkeypatch):
assert fingerprint_dir.exists()
assert pm.fingerprint_manager.current_fingerprint == fingerprint
key = Fernet.generate_key()
enc_mgr = EncryptionManager(key, fingerprint_dir)
vault = Vault(enc_mgr, fingerprint_dir)
vault, enc_mgr = create_vault(fingerprint_dir, TEST_SEED, TEST_PASSWORD)
entry_mgr = EntryManager(vault, fingerprint_dir)
pm.encryption_manager = enc_mgr

View File

@@ -1,7 +1,8 @@
import sys
from pathlib import Path
from tempfile import TemporaryDirectory
from cryptography.fernet import Fernet
from helpers import TEST_PASSWORD
from utils.key_derivation import derive_key_from_password
from mnemonic import Mnemonic
sys.path.append(str(Path(__file__).resolve().parents[1]))
@@ -12,7 +13,7 @@ from password_manager.manager import PasswordManager
def test_seed_encryption_round_trip():
with TemporaryDirectory() as tmpdir:
key = Fernet.generate_key()
key = derive_key_from_password(TEST_PASSWORD)
enc_mgr = EncryptionManager(key, Path(tmpdir))
seed = Mnemonic("english").generate(strength=128)

View File

@@ -5,13 +5,12 @@ from tempfile import TemporaryDirectory
from types import SimpleNamespace
from unittest.mock import patch
from cryptography.fernet import Fernet
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
sys.path.append(str(Path(__file__).resolve().parents[1]))
import main
from nostr.client import DEFAULT_RELAYS
from password_manager.encryption import EncryptionManager
from password_manager.config_manager import ConfigManager
from password_manager.vault import Vault
from utils.fingerprint_manager import FingerprintManager
@@ -26,8 +25,7 @@ def setup_pm(tmp_path, monkeypatch):
fp_dir = constants.APP_DIR / "fp"
fp_dir.mkdir(parents=True)
enc_mgr = EncryptionManager(Fernet.generate_key(), fp_dir)
vault = Vault(enc_mgr, fp_dir)
vault, enc_mgr = create_vault(fp_dir, TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, fp_dir)
fp_mgr = FingerprintManager(constants.APP_DIR)