From 00155237a56ee4903d8ecceabef09dfbf590441a Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 30 Jun 2025 11:17:55 -0400 Subject: [PATCH] Return success status from Nostr publish --- src/main.py | 12 +++++-- src/nostr/client.py | 24 ++++++++++--- src/tests/test_post_sync_messages.py | 27 ++++++++++++++ src/tests/test_publish_json_result.py | 52 +++++++++++++++++++++++++++ tests/test_nostr_backup.py | 5 +-- 5 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 src/tests/test_post_sync_messages.py create mode 100644 src/tests/test_publish_json_result.py diff --git a/src/main.py b/src/main.py index c5a1738..a60adee 100644 --- a/src/main.py +++ b/src/main.py @@ -215,9 +215,15 @@ def handle_post_to_nostr(password_manager: PasswordManager): encrypted_data = password_manager.get_encrypted_data() if encrypted_data: # Post to Nostr - password_manager.nostr_client.publish_json_to_nostr(encrypted_data) - print(colored("Encrypted index posted to Nostr successfully.", "green")) - logging.info("Encrypted index posted to Nostr successfully.") + success = password_manager.nostr_client.publish_json_to_nostr( + encrypted_data + ) + if success: + print(colored("\N{WHITE HEAVY CHECK MARK} Sync complete.", "green")) + logging.info("Encrypted index posted to Nostr successfully.") + else: + print(colored("\N{CROSS MARK} Sync failed…", "red")) + logging.error("Failed to post encrypted index to Nostr.") else: print(colored("No data available to post.", "yellow")) logging.warning("No data available to post to Nostr.") diff --git a/src/nostr/client.py b/src/nostr/client.py index b2e7e1c..7c807af 100644 --- a/src/nostr/client.py +++ b/src/nostr/client.py @@ -506,12 +506,24 @@ class NostrClient: ) raise - def publish_json_to_nostr(self, encrypted_json: bytes, to_pubkey: str = None): - """ - Public method to post encrypted JSON to Nostr. + def publish_json_to_nostr( + self, encrypted_json: bytes, to_pubkey: str | None = None + ) -> bool: + """Post encrypted JSON to Nostr. - :param encrypted_json: The encrypted JSON data to be sent. - :param to_pubkey: (Optional) The recipient's public key for encryption. + Parameters + ---------- + encrypted_json: + The encrypted JSON data to send. + to_pubkey: + Optional recipient public key. If provided the message will be NIP-4 + encrypted for that key. + + Returns + ------- + bool + ``True`` when the event is successfully published, ``False`` on + failure. """ try: encrypted_json_b64 = base64.b64encode(encrypted_json).decode("utf-8") @@ -538,11 +550,13 @@ class NostrClient: self.publish_event(event) logger.debug("Event published") + return True except Exception as e: logger.error(f"Failed to publish JSON to Nostr: {e}") logger.error(traceback.format_exc()) print(f"Error: Failed to publish JSON to Nostr: {e}", file=sys.stderr) + return False def retrieve_json_from_nostr_sync(self) -> Optional[bytes]: """ diff --git a/src/tests/test_post_sync_messages.py b/src/tests/test_post_sync_messages.py new file mode 100644 index 0000000..e13fe8f --- /dev/null +++ b/src/tests/test_post_sync_messages.py @@ -0,0 +1,27 @@ +import sys +from types import SimpleNamespace +from pathlib import Path + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +import main + + +def test_handle_post_success(capsys): + pm = SimpleNamespace( + get_encrypted_data=lambda: b"data", + nostr_client=SimpleNamespace(publish_json_to_nostr=lambda data: True), + ) + main.handle_post_to_nostr(pm) + out = capsys.readouterr().out + assert "✅ Sync complete." in out + + +def test_handle_post_failure(capsys): + pm = SimpleNamespace( + get_encrypted_data=lambda: b"data", + nostr_client=SimpleNamespace(publish_json_to_nostr=lambda data: False), + ) + main.handle_post_to_nostr(pm) + out = capsys.readouterr().out + assert "❌ Sync failed…" in out diff --git a/src/tests/test_publish_json_result.py b/src/tests/test_publish_json_result.py new file mode 100644 index 0000000..a0468ae --- /dev/null +++ b/src/tests/test_publish_json_result.py @@ -0,0 +1,52 @@ +import sys +from pathlib import Path +from tempfile import TemporaryDirectory +from unittest.mock import patch +from cryptography.fernet import Fernet + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from password_manager.encryption import EncryptionManager +from nostr.client import NostrClient + + +def setup_client(tmp_path): + key = Fernet.generate_key() + enc_mgr = EncryptionManager(key, tmp_path) + + with patch("nostr.client.ClientPool"), patch( + "nostr.client.KeyManager" + ), patch.object(NostrClient, "initialize_client_pool"), patch.object( + enc_mgr, "decrypt_parent_seed", return_value="seed" + ): + client = NostrClient(enc_mgr, "fp") + return client + + +class FakeEvent: + KIND_TEXT_NOTE = 1 + KIND_ENCRYPT = 2 + + def __init__(self, kind, content, pub_key): + self.kind = kind + self.content = content + self.pub_key = pub_key + self.id = "id" + + def sign(self, _): + pass + + +def test_publish_json_success(): + with TemporaryDirectory() as tmpdir, patch("nostr.client.Event", FakeEvent): + client = setup_client(Path(tmpdir)) + with patch.object(client, "publish_event") as mock_pub: + assert client.publish_json_to_nostr(b"data") is True + mock_pub.assert_called() + + +def test_publish_json_failure(): + with TemporaryDirectory() as tmpdir, patch("nostr.client.Event", FakeEvent): + client = setup_client(Path(tmpdir)) + with patch.object(client, "publish_event", side_effect=Exception("boom")): + assert client.publish_json_to_nostr(b"data") is False diff --git a/tests/test_nostr_backup.py b/tests/test_nostr_backup.py index 308e297..ee7c159 100644 --- a/tests/test_nostr_backup.py +++ b/tests/test_nostr_backup.py @@ -26,7 +26,7 @@ def test_backup_and_publish_to_nostr(): assert encrypted_index is not None with patch( - "nostr.client.NostrClient.publish_json_to_nostr" + "nostr.client.NostrClient.publish_json_to_nostr", return_value=True ) as mock_publish, patch("nostr.client.ClientPool"), patch( "nostr.client.KeyManager" ), patch.object( @@ -36,6 +36,7 @@ def test_backup_and_publish_to_nostr(): ): nostr_client = NostrClient(enc_mgr, "fp") entry_mgr.backup_index_file() - nostr_client.publish_json_to_nostr(encrypted_index) + result = nostr_client.publish_json_to_nostr(encrypted_index) mock_publish.assert_called_with(encrypted_index) + assert result is True