Add auto-sync mechanism for Nostr

This commit is contained in:
thePR0M3TH3AN
2025-06-30 00:09:41 -04:00
parent 7d65971fd3
commit ba175b48d1
3 changed files with 64 additions and 1 deletions

View File

@@ -5,6 +5,7 @@ import sys
import logging
import signal
import getpass
import time
from colorama import init as colorama_init
from termcolor import colored
import traceback
@@ -453,7 +454,7 @@ def handle_settings(password_manager: PasswordManager) -> None:
print(colored("Invalid choice.", "red"))
def display_menu(password_manager: PasswordManager):
def display_menu(password_manager: PasswordManager, sync_interval: float = 60.0):
"""
Displays the interactive menu and handles user input to perform various actions.
"""
@@ -466,6 +467,14 @@ def display_menu(password_manager: PasswordManager):
5. Exit
"""
while True:
# Periodically push updates to Nostr
if (
password_manager.is_dirty
and time.time() - password_manager.last_update >= sync_interval
):
handle_post_to_nostr(password_manager)
password_manager.is_dirty = False
# Flush logging handlers
for handler in logging.getLogger().handlers:
handler.flush()

View File

@@ -16,6 +16,7 @@ import getpass
import os
from typing import Optional
import shutil
import time
from termcolor import colored
from password_manager.encryption import EncryptionManager
@@ -47,6 +48,7 @@ from pathlib import Path
from local_bip85.bip85 import BIP85
from bip_utils import Bip39SeedGenerator, Bip39MnemonicGenerator, Bip39Languages
from datetime import datetime
from utils.fingerprint_manager import FingerprintManager
@@ -83,6 +85,10 @@ class PasswordManager:
self.nostr_client: Optional[NostrClient] = None
self.config_manager: Optional[ConfigManager] = None
# Track changes to trigger periodic Nostr sync
self.is_dirty: bool = False
self.last_update: float = time.time()
# Initialize the fingerprint manager first
self.initialize_fingerprint_manager()
@@ -735,6 +741,10 @@ class PasswordManager:
website_name, length, username, url, blacklisted=False
)
# Mark database as dirty for background sync
self.is_dirty = True
self.last_update = time.time()
# Generate the password using the assigned index
password = self.password_generator.generate_password(length, index)
@@ -911,6 +921,10 @@ class PasswordManager:
index, new_username, new_url, new_blacklisted
)
# Mark database as dirty for background sync
self.is_dirty = True
self.last_update = time.time()
print(colored(f"Entry updated successfully for index {index}.", "green"))
# Push the updated index to Nostr so changes are backed up.
@@ -949,6 +963,10 @@ class PasswordManager:
self.entry_manager.delete_entry(index_to_delete)
# Mark database as dirty for background sync
self.is_dirty = True
self.last_update = time.time()
# Push updated index to Nostr after deletion
try:
encrypted_data = self.get_encrypted_data()

View File

@@ -0,0 +1,36 @@
import time
from types import SimpleNamespace
from pathlib import Path
import pytest
import sys
sys.path.append(str(Path(__file__).resolve().parents[1]))
import main
def test_auto_sync_triggers_post(monkeypatch):
pm = SimpleNamespace(
is_dirty=True,
last_update=time.time() - 0.2,
nostr_client=SimpleNamespace(close_client_pool=lambda: None),
handle_add_password=lambda: None,
handle_retrieve_entry=lambda: None,
handle_modify_entry=lambda: None,
)
called = False
def fake_post(manager):
nonlocal called
called = True
monkeypatch.setattr(main, "handle_post_to_nostr", fake_post)
monkeypatch.setattr("builtins.input", lambda _: "5")
with pytest.raises(SystemExit):
main.display_menu(pm, sync_interval=0.1)
assert called
assert pm.is_dirty is False