Fix Nostr manifest handling

This commit is contained in:
thePR0M3TH3AN
2025-07-31 14:42:53 -04:00
parent f83234c568
commit ceb2eb28ad
3 changed files with 76 additions and 6 deletions

View File

@@ -406,6 +406,7 @@ def handle_retrieve_from_nostr(password_manager: PasswordManager):
Handles the action of retrieving the encrypted password index from Nostr. Handles the action of retrieving the encrypted password index from Nostr.
""" """
try: try:
password_manager.nostr_client.fingerprint = password_manager.current_fingerprint
result = asyncio.run(password_manager.nostr_client.fetch_latest_snapshot()) result = asyncio.run(password_manager.nostr_client.fetch_latest_snapshot())
if result: if result:
manifest, chunks = result manifest, chunks = result
@@ -423,8 +424,12 @@ def handle_retrieve_from_nostr(password_manager: PasswordManager):
print(colored("Encrypted index retrieved and saved successfully.", "green")) print(colored("Encrypted index retrieved and saved successfully.", "green"))
logging.info("Encrypted index retrieved and saved successfully from Nostr.") logging.info("Encrypted index retrieved and saved successfully from Nostr.")
else: else:
print(colored("Failed to retrieve data from Nostr.", "red")) msg = (
logging.error("Failed to retrieve data from Nostr.") f"No Nostr events found for fingerprint"
f" {password_manager.current_fingerprint}."
)
print(colored(msg, "red"))
logging.error(msg)
except Exception as e: except Exception as e:
logging.error(f"Failed to retrieve from Nostr: {e}", exc_info=True) logging.error(f"Failed to retrieve from Nostr: {e}", exc_info=True)
print(colored(f"Error: Failed to retrieve from Nostr: {e}", "red")) print(colored(f"Error: Failed to retrieve from Nostr: {e}", "red"))

View File

@@ -95,7 +95,7 @@ from datetime import datetime
from utils.fingerprint_manager import FingerprintManager from utils.fingerprint_manager import FingerprintManager
# Import NostrClient # Import NostrClient
from nostr.client import NostrClient, DEFAULT_RELAYS from nostr.client import NostrClient, DEFAULT_RELAYS, MANIFEST_ID_PREFIX
from .config_manager import ConfigManager from .config_manager import ConfigManager
from .state_manager import StateManager from .state_manager import StateManager
@@ -272,6 +272,8 @@ class PasswordManager:
def notify(self, message: str, level: str = "INFO") -> None: def notify(self, message: str, level: str = "INFO") -> None:
"""Enqueue a notification and set it as the active message.""" """Enqueue a notification and set it as the active message."""
note = Notification(message, level) note = Notification(message, level)
if not hasattr(self, "notifications"):
self.notifications = queue.Queue()
self.notifications.put(note) self.notifications.put(note)
self._current_notification = note self._current_notification = note
self._notification_expiry = time.time() + NOTIFICATION_DURATION self._notification_expiry = time.time() + NOTIFICATION_DURATION
@@ -605,6 +607,8 @@ class PasswordManager:
selected_fingerprint = fingerprints[int(choice) - 1] selected_fingerprint = fingerprints[int(choice) - 1]
self.fingerprint_manager.current_fingerprint = selected_fingerprint self.fingerprint_manager.current_fingerprint = selected_fingerprint
self.current_fingerprint = selected_fingerprint self.current_fingerprint = selected_fingerprint
if not getattr(self, "manifest_id", None):
self.manifest_id = f"{MANIFEST_ID_PREFIX}{selected_fingerprint}"
# Update fingerprint directory # Update fingerprint directory
self.fingerprint_dir = ( self.fingerprint_dir = (
@@ -645,7 +649,9 @@ class PasswordManager:
config_manager=getattr(self, "config_manager", None), config_manager=getattr(self, "config_manager", None),
parent_seed=getattr(self, "parent_seed", None), parent_seed=getattr(self, "parent_seed", None),
) )
if getattr(self, "manifest_id", None): if getattr(self, "manifest_id", None) and hasattr(
self.nostr_client, "_state_lock"
):
from nostr.backup_models import Manifest from nostr.backup_models import Manifest
with self.nostr_client._state_lock: with self.nostr_client._state_lock:
@@ -903,6 +909,8 @@ class PasswordManager:
self.current_fingerprint = fingerprint self.current_fingerprint = fingerprint
self.fingerprint_manager.current_fingerprint = fingerprint self.fingerprint_manager.current_fingerprint = fingerprint
self.fingerprint_dir = fingerprint_dir self.fingerprint_dir = fingerprint_dir
if not getattr(self, "manifest_id", None):
self.manifest_id = f"{MANIFEST_ID_PREFIX}{fingerprint}"
logging.info(f"Current seed profile set to {fingerprint}") logging.info(f"Current seed profile set to {fingerprint}")
try: try:
@@ -1174,7 +1182,9 @@ class PasswordManager:
parent_seed=getattr(self, "parent_seed", None), parent_seed=getattr(self, "parent_seed", None),
) )
if getattr(self, "manifest_id", None): if getattr(self, "manifest_id", None) and hasattr(
self.nostr_client, "_state_lock"
):
from nostr.backup_models import Manifest from nostr.backup_models import Manifest
with self.nostr_client._state_lock: with self.nostr_client._state_lock:
@@ -1197,6 +1207,8 @@ class PasswordManager:
"""Always fetch the latest vault data from Nostr and update the local index.""" """Always fetch the latest vault data from Nostr and update the local index."""
start = time.perf_counter() start = time.perf_counter()
try: try:
if getattr(self, "current_fingerprint", None):
self.nostr_client.fingerprint = self.current_fingerprint
result = await self.nostr_client.fetch_latest_snapshot() result = await self.nostr_client.fetch_latest_snapshot()
if not result: if not result:
if self.nostr_client.last_error: if self.nostr_client.last_error:
@@ -1346,6 +1358,8 @@ class PasswordManager:
have_data = False have_data = False
start = time.perf_counter() start = time.perf_counter()
try: try:
if getattr(self, "current_fingerprint", None):
self.nostr_client.fingerprint = self.current_fingerprint
result = await self.nostr_client.fetch_latest_snapshot() result = await self.nostr_client.fetch_latest_snapshot()
if result: if result:
manifest, chunks = result manifest, chunks = result
@@ -4308,7 +4322,9 @@ class PasswordManager:
parent_seed=getattr(self, "parent_seed", None), parent_seed=getattr(self, "parent_seed", None),
) )
if getattr(self, "manifest_id", None): if getattr(self, "manifest_id", None) and hasattr(
self.nostr_client, "_state_lock"
):
from nostr.backup_models import Manifest from nostr.backup_models import Manifest
with self.nostr_client._state_lock: with self.nostr_client._state_lock:

View File

@@ -0,0 +1,49 @@
from pathlib import Path
import main
from helpers import create_vault, dummy_nostr_client, TEST_SEED, TEST_PASSWORD
from seedpass.core.entry_management import EntryManager
from seedpass.core.backup import BackupManager
from seedpass.core.config_manager import ConfigManager
from seedpass.core.manager import PasswordManager, EncryptionMode
def _init_pm(dir_path: Path, client) -> PasswordManager:
vault, enc_mgr = create_vault(dir_path, TEST_SEED, TEST_PASSWORD)
cfg_mgr = ConfigManager(vault, dir_path)
backup_mgr = BackupManager(dir_path, cfg_mgr)
entry_mgr = EntryManager(vault, backup_mgr)
pm = PasswordManager.__new__(PasswordManager)
pm.encryption_mode = EncryptionMode.SEED_ONLY
pm.encryption_manager = enc_mgr
pm.vault = vault
pm.entry_manager = entry_mgr
pm.backup_manager = backup_mgr
pm.config_manager = cfg_mgr
pm.nostr_client = client
pm.fingerprint_dir = dir_path
pm.current_fingerprint = "fp"
pm.is_dirty = False
return pm
def test_restore_flow_from_snapshot(monkeypatch, tmp_path):
client, relay = dummy_nostr_client.__wrapped__(tmp_path / "srv", monkeypatch)
dir_a = tmp_path / "A"
dir_b = tmp_path / "B"
dir_a.mkdir()
dir_b.mkdir()
pm_a = _init_pm(dir_a, client)
pm_a.entry_manager.add_entry("site1", 12)
pm_a.sync_vault()
assert relay.manifests
pm_b = _init_pm(dir_b, client)
monkeypatch.setattr(main, "pause", lambda *a, **k: None)
main.handle_retrieve_from_nostr(pm_b)
labels = [e[1] for e in pm_b.entry_manager.list_entries()]
assert labels == ["site1"]