mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-08 23:38:49 +00:00
Update tests for entries schema
This commit is contained in:
@@ -35,7 +35,7 @@ class BackupManager:
|
||||
timestamped filenames to facilitate easy identification and retrieval.
|
||||
"""
|
||||
|
||||
BACKUP_FILENAME_TEMPLATE = "passwords_db_backup_{timestamp}.json.enc"
|
||||
BACKUP_FILENAME_TEMPLATE = "entries_db_backup_{timestamp}.json.enc"
|
||||
|
||||
def __init__(self, fingerprint_dir: Path):
|
||||
"""
|
||||
@@ -47,7 +47,7 @@ class BackupManager:
|
||||
self.fingerprint_dir = fingerprint_dir
|
||||
self.backup_dir = self.fingerprint_dir / "backups"
|
||||
self.backup_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.index_file = self.fingerprint_dir / "seedpass_passwords_db.json.enc"
|
||||
self.index_file = self.fingerprint_dir / "seedpass_entries_db.json.enc"
|
||||
logger.debug(
|
||||
f"BackupManager initialized with backup directory at {self.backup_dir}"
|
||||
)
|
||||
@@ -79,7 +79,7 @@ class BackupManager:
|
||||
def restore_latest_backup(self) -> None:
|
||||
try:
|
||||
backup_files = sorted(
|
||||
self.backup_dir.glob("passwords_db_backup_*.json.enc"),
|
||||
self.backup_dir.glob("entries_db_backup_*.json.enc"),
|
||||
key=lambda x: x.stat().st_mtime,
|
||||
reverse=True,
|
||||
)
|
||||
@@ -112,7 +112,7 @@ class BackupManager:
|
||||
def list_backups(self) -> None:
|
||||
try:
|
||||
backup_files = sorted(
|
||||
self.backup_dir.glob("passwords_db_backup_*.json.enc"),
|
||||
self.backup_dir.glob("entries_db_backup_*.json.enc"),
|
||||
key=lambda x: x.stat().st_mtime,
|
||||
reverse=True,
|
||||
)
|
||||
|
@@ -246,10 +246,10 @@ class EncryptionManager:
|
||||
|
||||
:param data: The JSON data to save.
|
||||
:param relative_path: The relative path within the fingerprint directory where data will be saved.
|
||||
Defaults to 'seedpass_passwords_db.json.enc'.
|
||||
Defaults to 'seedpass_entries_db.json.enc'.
|
||||
"""
|
||||
if relative_path is None:
|
||||
relative_path = Path("seedpass_passwords_db.json.enc")
|
||||
relative_path = Path("seedpass_entries_db.json.enc")
|
||||
try:
|
||||
json_data = json.dumps(data, indent=4).encode("utf-8")
|
||||
self.encrypt_and_save_file(json_data, relative_path)
|
||||
@@ -273,11 +273,11 @@ class EncryptionManager:
|
||||
Decrypts and loads JSON data from the specified relative path within the fingerprint directory.
|
||||
|
||||
:param relative_path: The relative path within the fingerprint directory from which data will be loaded.
|
||||
Defaults to 'seedpass_passwords_db.json.enc'.
|
||||
Defaults to 'seedpass_entries_db.json.enc'.
|
||||
:return: The decrypted JSON data as a dictionary.
|
||||
"""
|
||||
if relative_path is None:
|
||||
relative_path = Path("seedpass_passwords_db.json.enc")
|
||||
relative_path = Path("seedpass_entries_db.json.enc")
|
||||
|
||||
file_path = self.fingerprint_dir / relative_path
|
||||
|
||||
@@ -320,10 +320,10 @@ class EncryptionManager:
|
||||
Updates the checksum file for the specified file within the fingerprint directory.
|
||||
|
||||
:param relative_path: The relative path within the fingerprint directory for which the checksum will be updated.
|
||||
Defaults to 'seedpass_passwords_db.json.enc'.
|
||||
Defaults to 'seedpass_entries_db.json.enc'.
|
||||
"""
|
||||
if relative_path is None:
|
||||
relative_path = Path("seedpass_passwords_db.json.enc")
|
||||
relative_path = Path("seedpass_entries_db.json.enc")
|
||||
try:
|
||||
file_path = self.fingerprint_dir / relative_path
|
||||
logger.debug("Calculating checksum of the encrypted file bytes.")
|
||||
@@ -368,7 +368,7 @@ class EncryptionManager:
|
||||
:return: Encrypted data as bytes or None if the index file does not exist.
|
||||
"""
|
||||
try:
|
||||
relative_path = Path("seedpass_passwords_db.json.enc")
|
||||
relative_path = Path("seedpass_entries_db.json.enc")
|
||||
if not (self.fingerprint_dir / relative_path).exists():
|
||||
logger.error(
|
||||
f"Index file '{relative_path}' does not exist in '{self.fingerprint_dir}'."
|
||||
@@ -407,10 +407,10 @@ class EncryptionManager:
|
||||
|
||||
:param encrypted_data: The encrypted data retrieved from Nostr.
|
||||
:param relative_path: The relative path within the fingerprint directory to update.
|
||||
Defaults to 'seedpass_passwords_db.json.enc'.
|
||||
Defaults to 'seedpass_entries_db.json.enc'.
|
||||
"""
|
||||
if relative_path is None:
|
||||
relative_path = Path("seedpass_passwords_db.json.enc")
|
||||
relative_path = Path("seedpass_entries_db.json.enc")
|
||||
try:
|
||||
decrypted_data = self.decrypt_data(encrypted_data)
|
||||
data = json.loads(decrypted_data.decode("utf-8"))
|
||||
|
@@ -50,8 +50,8 @@ class EntryManager:
|
||||
self.fingerprint_dir = fingerprint_dir
|
||||
|
||||
# Use paths relative to the fingerprint directory
|
||||
self.index_file = self.fingerprint_dir / "seedpass_passwords_db.json.enc"
|
||||
self.checksum_file = self.fingerprint_dir / "seedpass_passwords_db_checksum.txt"
|
||||
self.index_file = self.fingerprint_dir / "seedpass_entries_db.json.enc"
|
||||
self.checksum_file = self.fingerprint_dir / "seedpass_entries_db_checksum.txt"
|
||||
|
||||
logger.debug(f"EntryManager initialized with index file at {self.index_file}")
|
||||
|
||||
@@ -410,7 +410,7 @@ class EntryManager:
|
||||
return
|
||||
|
||||
timestamp = int(time.time())
|
||||
backup_filename = f"passwords_db_backup_{timestamp}.json.enc"
|
||||
backup_filename = f"entries_db_backup_{timestamp}.json.enc"
|
||||
backup_path = self.fingerprint_dir / backup_filename
|
||||
|
||||
with open(index_file_path, "rb") as original_file, open(
|
||||
|
@@ -769,7 +769,7 @@ class PasswordManager:
|
||||
|
||||
def sync_index_from_nostr_if_missing(self) -> None:
|
||||
"""Retrieve the password database from Nostr if it doesn't exist locally."""
|
||||
index_file = self.fingerprint_dir / "seedpass_passwords_db.json.enc"
|
||||
index_file = self.fingerprint_dir / "seedpass_entries_db.json.enc"
|
||||
if index_file.exists():
|
||||
return
|
||||
try:
|
||||
|
@@ -10,7 +10,7 @@ from .encryption import EncryptionManager
|
||||
class Vault:
|
||||
"""Simple wrapper around :class:`EncryptionManager` for vault storage."""
|
||||
|
||||
INDEX_FILENAME = "seedpass_passwords_db.json.enc"
|
||||
INDEX_FILENAME = "seedpass_entries_db.json.enc"
|
||||
CONFIG_FILENAME = "seedpass_config.json.enc"
|
||||
|
||||
def __init__(
|
||||
|
@@ -17,7 +17,7 @@ def test_backup_restore_workflow(monkeypatch):
|
||||
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"
|
||||
index_file = fp_dir / "seedpass_entries_db.json.enc"
|
||||
|
||||
data1 = {
|
||||
"schema_version": 2,
|
||||
@@ -30,7 +30,7 @@ def test_backup_restore_workflow(monkeypatch):
|
||||
|
||||
monkeypatch.setattr(time, "time", lambda: 1111)
|
||||
backup_mgr.create_backup()
|
||||
backup1 = fp_dir / "backups" / "passwords_db_backup_1111.json.enc"
|
||||
backup1 = fp_dir / "backups" / "entries_db_backup_1111.json.enc"
|
||||
assert backup1.exists()
|
||||
assert backup1.stat().st_mode & 0o777 == 0o600
|
||||
|
||||
@@ -45,7 +45,7 @@ def test_backup_restore_workflow(monkeypatch):
|
||||
|
||||
monkeypatch.setattr(time, "time", lambda: 2222)
|
||||
backup_mgr.create_backup()
|
||||
backup2 = fp_dir / "backups" / "passwords_db_backup_2222.json.enc"
|
||||
backup2 = fp_dir / "backups" / "entries_db_backup_2222.json.enc"
|
||||
assert backup2.exists()
|
||||
assert backup2.stat().st_mode & 0o777 == 0o600
|
||||
|
||||
|
@@ -21,8 +21,8 @@ def test_encryption_checksum_workflow():
|
||||
manager.save_json_data(data)
|
||||
manager.update_checksum()
|
||||
|
||||
enc_file = tmp_path / "seedpass_passwords_db.json.enc"
|
||||
chk_file = tmp_path / "seedpass_passwords_db.json_checksum.txt"
|
||||
enc_file = tmp_path / "seedpass_entries_db.json.enc"
|
||||
chk_file = tmp_path / "seedpass_entries_db.json_checksum.txt"
|
||||
|
||||
checksum = chk_file.read_text().strip()
|
||||
assert re.fullmatch(r"[0-9a-f]{64}", checksum)
|
||||
|
@@ -20,7 +20,7 @@ def test_json_save_and_load_round_trip():
|
||||
loaded = manager.load_json_data()
|
||||
assert loaded == data
|
||||
|
||||
file_path = Path(tmpdir) / "seedpass_passwords_db.json.enc"
|
||||
file_path = Path(tmpdir) / "seedpass_entries_db.json.enc"
|
||||
raw = file_path.read_bytes()
|
||||
assert raw != json.dumps(data, indent=4).encode("utf-8")
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
import pytest
|
||||
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
|
||||
|
||||
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
||||
@@ -30,3 +31,30 @@ def test_add_and_retrieve_entry():
|
||||
data = enc_mgr.load_json_data(entry_mgr.index_file)
|
||||
assert str(index) in data.get("entries", {})
|
||||
assert data["entries"][str(index)] == entry
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"method, expected_type",
|
||||
[
|
||||
("add_entry", "password"),
|
||||
("add_totp", "totp"),
|
||||
("add_ssh_key", "ssh"),
|
||||
("add_seed", "seed"),
|
||||
],
|
||||
)
|
||||
def test_round_trip_entry_types(method, expected_type):
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
vault, enc_mgr = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
|
||||
entry_mgr = EntryManager(vault, Path(tmpdir))
|
||||
|
||||
if method == "add_entry":
|
||||
index = entry_mgr.add_entry("example.com", 8)
|
||||
else:
|
||||
with pytest.raises(NotImplementedError):
|
||||
getattr(entry_mgr, method)()
|
||||
index = 0
|
||||
|
||||
entry = entry_mgr.retrieve_entry(index)
|
||||
assert entry["type"] == expected_type
|
||||
data = enc_mgr.load_json_data(entry_mgr.index_file)
|
||||
assert data["entries"][str(index)]["type"] == expected_type
|
||||
|
@@ -19,7 +19,7 @@ def test_update_checksum_writes_to_expected_path():
|
||||
vault.save_index({"entries": {}})
|
||||
entry_mgr.update_checksum()
|
||||
|
||||
expected = tmp_path / "seedpass_passwords_db_checksum.txt"
|
||||
expected = tmp_path / "seedpass_entries_db_checksum.txt"
|
||||
assert expected.exists()
|
||||
|
||||
|
||||
@@ -32,5 +32,5 @@ def test_backup_index_file_creates_backup_in_directory():
|
||||
vault.save_index({"entries": {}})
|
||||
entry_mgr.backup_index_file()
|
||||
|
||||
backups = list(tmp_path.glob("passwords_db_backup_*.json.enc"))
|
||||
backups = list(tmp_path.glob("entries_db_backup_*.json.enc"))
|
||||
assert len(backups) == 1
|
||||
|
@@ -64,9 +64,9 @@ def test_manager_workflow(monkeypatch):
|
||||
|
||||
pm.handle_add_password()
|
||||
assert pm.is_dirty is False
|
||||
backups = list(tmp_path.glob("passwords_db_backup_*.json.enc"))
|
||||
backups = list(tmp_path.glob("entries_db_backup_*.json.enc"))
|
||||
assert len(backups) == 1
|
||||
checksum_file = tmp_path / "seedpass_passwords_db_checksum.txt"
|
||||
checksum_file = tmp_path / "seedpass_entries_db_checksum.txt"
|
||||
assert checksum_file.exists()
|
||||
checksum_after_add = checksum_file.read_text()
|
||||
first_post = pm.nostr_client.published[-1]
|
||||
@@ -79,7 +79,7 @@ def test_manager_workflow(monkeypatch):
|
||||
assert pm.is_dirty is False
|
||||
pm.backup_manager.create_backup()
|
||||
backup_dir = tmp_path / "backups"
|
||||
backups_mod = list(backup_dir.glob("passwords_db_backup_*.json.enc"))
|
||||
backups_mod = list(backup_dir.glob("entries_db_backup_*.json.enc"))
|
||||
assert backups_mod
|
||||
checksum_after_modify = checksum_file.read_text()
|
||||
assert checksum_after_modify != checksum_after_add
|
||||
|
@@ -23,6 +23,21 @@ def test_migrate_v0_to_v2(tmp_path: Path):
|
||||
assert data["entries"]["0"] == expected_entry
|
||||
|
||||
|
||||
def test_migrate_v1_to_v2(tmp_path: Path):
|
||||
enc_mgr, vault = setup(tmp_path)
|
||||
legacy = {"schema_version": 1, "passwords": {"0": {"website": "b", "length": 10}}}
|
||||
enc_mgr.save_json_data(legacy)
|
||||
data = vault.load_index()
|
||||
assert data["schema_version"] == LATEST_VERSION
|
||||
expected_entry = {
|
||||
"website": "b",
|
||||
"length": 10,
|
||||
"type": "password",
|
||||
"notes": "",
|
||||
}
|
||||
assert data["entries"]["0"] == expected_entry
|
||||
|
||||
|
||||
def test_error_on_future_version(tmp_path: Path):
|
||||
enc_mgr, vault = setup(tmp_path)
|
||||
future = {"schema_version": LATEST_VERSION + 1, "entries": {}}
|
||||
|
@@ -6,6 +6,7 @@ from hypothesis import given, strategies as st, settings
|
||||
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from password_manager.password_generation import PasswordGenerator
|
||||
from password_manager.entry_types import EntryType
|
||||
|
||||
|
||||
class DummyEnc:
|
||||
@@ -32,8 +33,10 @@ def make_generator():
|
||||
@settings(deadline=None)
|
||||
def test_password_properties(length, index):
|
||||
pg = make_generator()
|
||||
entry_type = EntryType.PASSWORD.value
|
||||
pw1 = pg.generate_password(length=length, index=index)
|
||||
pw2 = pg.generate_password(length=length, index=index)
|
||||
assert entry_type == "password"
|
||||
|
||||
assert pw1 == pw2
|
||||
assert len(pw1) == length
|
||||
|
Reference in New Issue
Block a user