diff --git a/src/password_manager/manager.py b/src/password_manager/manager.py index e969f63..cd651c0 100644 --- a/src/password_manager/manager.py +++ b/src/password_manager/manager.py @@ -187,6 +187,7 @@ class PasswordManager: self.initialize_managers() self.locked = False self.update_activity() + self.sync_index_from_nostr() def initialize_fingerprint_manager(self): """ @@ -833,6 +834,29 @@ class PasswordManager: print(colored(f"Error: Failed to initialize managers: {e}", "red")) sys.exit(1) + def sync_index_from_nostr(self) -> None: + """Always fetch the latest vault data from Nostr and update the local index.""" + try: + result = asyncio.run(self.nostr_client.fetch_latest_snapshot()) + if not result: + return + manifest, chunks = result + encrypted = gzip.decompress(b"".join(chunks)) + if manifest.delta_since: + try: + version = int(manifest.delta_since) + deltas = asyncio.run(self.nostr_client.fetch_deltas_since(version)) + if deltas: + encrypted = deltas[-1] + except ValueError: + pass + current = self.vault.get_encrypted_index() + if current != encrypted: + self.vault.decrypt_and_save_index_from_nostr(encrypted) + logger.info("Local database synchronized from Nostr.") + except Exception as e: + logger.warning(f"Unable to sync index from Nostr: {e}") + 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_entries_db.json.enc" diff --git a/src/tests/test_password_unlock_after_change.py b/src/tests/test_password_unlock_after_change.py index 22b8d6c..114b7f1 100644 --- a/src/tests/test_password_unlock_after_change.py +++ b/src/tests/test_password_unlock_after_change.py @@ -81,6 +81,7 @@ def test_password_change_and_unlock(monkeypatch): ) monkeypatch.setattr(PasswordManager, "initialize_bip85", lambda self: None) monkeypatch.setattr(PasswordManager, "initialize_managers", lambda self: None) + monkeypatch.setattr(PasswordManager, "sync_index_from_nostr", lambda self: None) pm.unlock_vault() diff --git a/src/tests/test_unlock_sync.py b/src/tests/test_unlock_sync.py new file mode 100644 index 0000000..7eef4c5 --- /dev/null +++ b/src/tests/test_unlock_sync.py @@ -0,0 +1,26 @@ +import time +from types import SimpleNamespace +from pathlib import Path +import sys + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from password_manager.manager import PasswordManager + + +def test_unlock_triggers_sync(monkeypatch, tmp_path): + pm = PasswordManager.__new__(PasswordManager) + pm.fingerprint_dir = tmp_path + pm.setup_encryption_manager = lambda *a, **k: None + pm.initialize_bip85 = lambda: None + pm.initialize_managers = lambda: None + called = {"sync": False} + + def fake_sync(self): + called["sync"] = True + + monkeypatch.setattr(PasswordManager, "sync_index_from_nostr", fake_sync) + + pm.unlock_vault() + + assert called["sync"]