From ba066bf0d4cc133b98c5e9a2ef8e7295e2542857 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 14 Jul 2025 14:16:59 -0400 Subject: [PATCH] Run sync in background for TUI actions --- src/password_manager/manager.py | 35 +++++++++++++++++++--------- src/tests/test_manager_add_totp.py | 4 +++- src/tests/test_manager_workflow.py | 6 +++++ src/tests/test_profile_management.py | 5 ++++ 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/password_manager/manager.py b/src/password_manager/manager.py index 4a1a8a2..9b60b4e 100644 --- a/src/password_manager/manager.py +++ b/src/password_manager/manager.py @@ -1102,6 +1102,19 @@ class PasswordManager: self._relay_thread = threading.Thread(target=_worker, daemon=True) self._relay_thread.start() + def start_background_vault_sync(self, alt_summary: str | None = None) -> None: + """Publish the vault to Nostr in a background thread.""" + if getattr(self, "offline_mode", False): + return + + def _worker() -> None: + try: + self.sync_vault(alt_summary=alt_summary) + except Exception as exc: + logging.error(f"Background vault sync failed: {exc}", exc_info=True) + + threading.Thread(target=_worker, daemon=True).start() + def sync_index_from_nostr_if_missing(self) -> None: """Retrieve the password database from Nostr if it doesn't exist locally. @@ -1225,7 +1238,7 @@ class PasswordManager: # Automatically push the updated encrypted index to Nostr so the # latest changes are backed up remotely. try: - self.sync_vault() + self.start_background_vault_sync() logging.info("Encrypted index posted to Nostr after entry addition.") except Exception as nostr_error: logging.error( @@ -1299,7 +1312,7 @@ class PasswordManager: TotpManager.print_qr_code(uri) print(color_text(f"Secret: {secret}\n", "deterministic")) try: - self.sync_vault() + self.start_background_vault_sync() except Exception as nostr_error: logging.error( f"Failed to post updated index to Nostr: {nostr_error}", @@ -1348,7 +1361,7 @@ class PasswordManager: ) TotpManager.print_qr_code(uri) try: - self.sync_vault() + self.start_background_vault_sync() except Exception as nostr_error: logging.error( f"Failed to post updated index to Nostr: {nostr_error}", @@ -1411,7 +1424,7 @@ class PasswordManager: print(colored("Private Key:", "cyan")) print(color_text(priv_pem, "deterministic")) try: - self.sync_vault() + self.start_background_vault_sync() except Exception as nostr_error: logging.error( f"Failed to post updated index to Nostr: {nostr_error}", @@ -1479,7 +1492,7 @@ class PasswordManager: TotpManager.print_qr_code(encode_seedqr(phrase)) try: - self.sync_vault() + self.start_background_vault_sync() except Exception as nostr_error: logging.error( f"Failed to post updated index to Nostr: {nostr_error}", @@ -1545,7 +1558,7 @@ class PasswordManager: print(colored(f"Fingerprint: {fingerprint}", "cyan")) print(color_text(priv_key, "deterministic")) try: - self.sync_vault() + self.start_background_vault_sync() except Exception as nostr_error: # pragma: no cover - best effort logging.error( f"Failed to post updated index to Nostr: {nostr_error}", @@ -1601,7 +1614,7 @@ class PasswordManager: ): TotpManager.print_qr_code(nsec) try: - self.sync_vault() + self.start_background_vault_sync() except Exception as nostr_error: # pragma: no cover - best effort logging.error( f"Failed to post updated index to Nostr: {nostr_error}", @@ -1676,7 +1689,7 @@ class PasswordManager: else: print(color_text(f"Value: {value}", "deterministic")) try: - self.sync_vault() + self.start_background_vault_sync() except Exception as nostr_error: # pragma: no cover - best effort logging.error( f"Failed to post updated index to Nostr: {nostr_error}", @@ -1737,7 +1750,7 @@ class PasswordManager: TotpManager.print_qr_code(encode_seedqr(seed)) try: - self.sync_vault() + self.start_background_vault_sync() except Exception as nostr_error: # pragma: no cover - best effort logging.error( f"Failed to post updated index to Nostr: {nostr_error}", @@ -2772,7 +2785,7 @@ class PasswordManager: # Push the updated index to Nostr so changes are backed up. try: - self.sync_vault() + self.start_background_vault_sync() logging.info( "Encrypted index posted to Nostr after entry modification." ) @@ -3045,7 +3058,7 @@ class PasswordManager: # Push updated index to Nostr after deletion try: - self.sync_vault() + self.start_background_vault_sync() logging.info("Encrypted index posted to Nostr after entry deletion.") except Exception as nostr_error: logging.error( diff --git a/src/tests/test_manager_add_totp.py b/src/tests/test_manager_add_totp.py index c011d3e..3dd140a 100644 --- a/src/tests/test_manager_add_totp.py +++ b/src/tests/test_manager_add_totp.py @@ -52,7 +52,9 @@ def test_handle_add_totp(monkeypatch, capsys): ] ) monkeypatch.setattr("builtins.input", lambda *args, **kwargs: next(inputs)) - monkeypatch.setattr(pm, "sync_vault", lambda: None) + monkeypatch.setattr( + pm, "start_background_vault_sync", lambda *a, **k: pm.sync_vault(*a, **k) + ) pm.handle_add_totp() out = capsys.readouterr().out diff --git a/src/tests/test_manager_workflow.py b/src/tests/test_manager_workflow.py index 5d2dbd0..a5046b2 100644 --- a/src/tests/test_manager_workflow.py +++ b/src/tests/test_manager_workflow.py @@ -71,6 +71,12 @@ def test_manager_workflow(monkeypatch): ) monkeypatch.setattr("builtins.input", lambda *args, **kwargs: next(inputs)) + monkeypatch.setattr( + pm, + "start_background_vault_sync", + lambda *a, **k: pm.sync_vault(*a, **k), + ) + pm.handle_add_password() assert pm.is_dirty is False backups = list((tmp_path / "backups").glob("entries_db_backup_*.json.enc")) diff --git a/src/tests/test_profile_management.py b/src/tests/test_profile_management.py index ae5dcce..bbb52de 100644 --- a/src/tests/test_profile_management.py +++ b/src/tests/test_profile_management.py @@ -74,6 +74,11 @@ def test_add_and_delete_entry(monkeypatch): inputs = iter([str(index)]) monkeypatch.setattr("builtins.input", lambda *_a, **_k: next(inputs)) + monkeypatch.setattr( + pm, + "start_background_vault_sync", + lambda *a, **k: pm.sync_vault(*a, **k), + ) pm.delete_entry()