mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-08 15:28:44 +00:00
Merge pull request #701 from PR0M3TH3AN/codex/verify-and-improve-manifest-identifier-handling
Fix manifest ID handling and add restore test
This commit is contained in:
@@ -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"))
|
||||||
|
@@ -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:
|
||||||
|
49
src/tests/test_nostr_restore_flow.py
Normal file
49
src/tests/test_nostr_restore_flow.py
Normal 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"]
|
Reference in New Issue
Block a user